如何访问.then()链中的先前的诺言结果?


650

我已经将我的代码重组为promises,并构建了一个美好的长而平坦的promise链,其中包括多个.then()回调。最后,我想返回一些复合值,并且需要访问多个中间promise结果。但是,序列中间的分辨率值不在上一个回调的范围内,如何访问它们?

function getExample() {
    return promiseA(…).then(function(resultA) {
        // Some processing
        return promiseB(…);
    }).then(function(resultB) {
        // More processing
        return // How do I gain access to resultA here?
    });
}

2
这个问题确实很有趣,即使被标记了javascript,它也与其他语言相关。我只是在java和jdeferred中使用“打破链条”答案
gontard

Answers:


377

断链

当需要访问链中的中间值时,应将链分成所需的单个部分。不必附加一个回调并以某种方式尝试多次使用其参数,而是将多个回调附加到同一promise-无论何时需要结果值。不要忘记,承诺只是代表(代理)未来的价值!除了从线性链中的另一个承诺中推导一个承诺之外,还使用库提供给您的承诺组合器来构建结果值。

这将导致非常简单的控制流程,清晰的功能组合,因此易于模块化。

function getExample() {
    var a = promiseA(…);
    var b = a.then(function(resultA) {
        // some processing
        return promiseB(…);
    });
    return Promise.all([a, b]).then(function([resultA, resultB]) {
        // more processing
        return // something using both resultA and resultB
    });
}

相反,在回调参数解体后Promise.all,只有变得可用ES6,在ES5的then通话将被认为是由许多承诺库提供一个极好的辅助方法代替(Q蓝鸟,...) .spread(function(resultA, resultB) { …

蓝鸟还具有专用join功能,可将其Promise.all+ spread组合替换为更简单(且效率更高)的结构:


return Promise.join(a, b, function(resultA, resultB) {  });

1
数组中的函数是否按顺序执行?
scaryguy

6
@scaryguy:数组中没有函数,这些是promise。promiseApromiseB是(承诺返流)的功能在这里。
Bergi 2015年

2
@Roland从没说过:-)这个答案是在ES5时代写的,当时根本没有任何标准,spread在这种模式下超级有用。有关更现代的解决方案,请参见公认的答案。但是,我已经更新了显式传递的答案,确实没有充分的理由不更新此答案
贝尔吉'17

1
@reify不,您不应该这样做,这会给拒绝带来麻烦。
Bergi

1
我不明白这个例子。如果有一串“ then”语句要求值在整个链中传播,那么我看不出这是如何解决问题的。在存在该值之前,无法触发(创建)需要先前值的Promise。此外,Promise.all()只是等待列表中的所有Promise完成:它不施加命令。因此,我需要每个“下一个”函数都可以访问所有先前的值,而我看不到您的示例如何做到这一点。您应该向我们介绍您的示例,因为我不相信或不理解它。
David Spector

238

ECMAScript和声

当然,语言设计者也意识到了这个问题。他们做了很多工作,异步功能提案最终使它成为了

ECMAScript 8

您不再需要单个then调用或回调函数,因为在异步函数(被调用时返回一个Promise)中,您可以直接等待Promise直接解析。它还具有诸如条件,循环和try-catch-clauses之类的任意控制结构,但是为了方便起见,我们在这里不需要它们:

async function getExample() {
    var resultA = await promiseA(…);
    // some processing
    var resultB = await promiseB(…);
    // more processing
    return // something using both resultA and resultB
}

ECMAScript 6

在等待ES8时,我们确实使用了非常相似的语法。ES6带有生成器功能,该功能允许按任意放置的yield关键字将执行分段。这些切片可以彼此独立,甚至异步地运行-这就是我们要在运行下一步之前等待promise解析时所要做的。

有专用的库(例如cotask.js),但是还有许多Promise库具有辅助函数(QBluebirdwhen …),当您为它们提供生成器函数时,它们会为您逐步执行异步操作产生希望。

var getExample = Promise.coroutine(function* () {
//               ^^^^^^^^^^^^^^^^^ Bluebird syntax
    var resultA = yield promiseA(…);
    // some processing
    var resultB = yield promiseB(…);
    // more processing
    return // something using both resultA and resultB
});

从4.0版本开始,它确实在Node.js中起作用,而且一些浏览器(或其开发版本)相对较早地支持生成器语法。

ECMAScript 5

但是,如果您希望/需要向后兼容,那么在没有编译器的情况下不能使用它们。当前工具支持生成器功能和异步功能,例如,请参见Babel有关生成器异步功能的文档。

然后,还有许多其他的JS编译语言 致力于简化异步编程。他们通常使用类似语法await(例如冰的CoffeeScript),但也有其他人配备了哈斯克尔样do-notation(如LatteJs一元PureScriptLispyScript)。


@Bergi是否需要等待来自外部代码的异步函数示例getExample()?
arisalexis

@arisalexis:是的,getExample它仍然是一个返回promise的函数,其作用与其他答案中的函数相同,但语法更好。您可以await调用另一个async函数,也可以链接.then()到其结果。
Bergi 2015年

1
我很好奇,为什么问完之后马上回答自己的问题?这里有一些很好的讨论,但我很好奇。也许您问完后就自己找到了答案?
granmoe '16

@granmoe:我故意将整个讨论发布为一个规范的重复目标
Bergi,2016年

在ECMAScript 6示例中,是否有一种(不太费力的)方法来避免使用Promise.coroutine(即,不使用Bluebird或其他库,而仅使用纯JS)?我想到过类似的东西,steps.next().value.then(steps.next)...但是那没用。
学习者没有名字,名称为

102

同步检查

将变量的后赋值分配给变量,然后通过同步检查获取它们的值。该示例使用bluebird的.value()方法,但是许多库提供了类似的方法。

function getExample() {
    var a = promiseA(…);

    return a.then(function() {
        // some processing
        return promiseB(…);
    }).then(function(resultB) {
        // a is guaranteed to be fulfilled here so we can just retrieve its
        // value synchronously
        var aValue = a.value();
    });
}

可以根据需要使用多个值:

function getExample() {
    var a = promiseA(…);

    var b = a.then(function() {
        return promiseB(…)
    });

    var c = b.then(function() {
        return promiseC(…);
    });

    var d = c.then(function() {
        return promiseD(…);
    });

    return d.then(function() {
        return a.value() + b.value() + c.value() + d.value();
    });
}

6
这是我最喜欢的答案:对库或语言功能的可读性,可扩展性和最小程度的依赖
Jason

13
@Jason:嗯,“ 对图书馆功能的最小依赖 ”?同步检查是一种库功能,是一种非常不标准的启动功能。
Bergi 2016年

2
我认为他指的是图书馆的特定功能
Deathgaze

54

嵌套(和)闭包

使用闭包来维护变量的范围(在我们的示例中为成功回调函数参数)是自然的JavaScript解决方案。有了promise,我们可以随意嵌套和展平 .then()回调,它们在语义上是等效的,但内部回调的范围除外。

function getExample() {
    return promiseA(…).then(function(resultA) {
        // some processing
        return promiseB(…).then(function(resultB) {
            // more processing
            return // something using both resultA and resultB;
        });
    });
}

当然,这是在构建压痕金字塔。如果缩进变得太大,您仍然可以使用旧工具来反击厄运金字塔:模块化,使用额外的命名函数以及在不再需要变量时立即平整承诺链。
从理论上讲,您总是可以避免两个以上的嵌套级别(通过使所有闭包都明确),实际上可以使用尽可能多的嵌套。

function getExample() {
    // preprocessing
    return promiseA(…).then(makeAhandler(…));
}
function makeAhandler(…)
    return function(resultA) {
        // some processing
        return promiseB(…).then(makeBhandler(resultA, …));
    };
}
function makeBhandler(resultA, …) {
    return function(resultB) {
        // more processing
        return // anything that uses the variables in scope
    };
}

您还可以使用辅助功能对于这种局部的应用,如_.partial下划线 / lodash本地.bind()方法,以进一步降低缩进:

function getExample() {
    // preprocessing
    return promiseA(…).then(handlerA);
}
function handlerA(resultA) {
    // some processing
    return promiseB(…).then(handlerB.bind(null, resultA));
}
function handlerB(resultA, resultB) {
    // more processing
    return // anything that uses resultA and resultB
}

5
诺兰·劳森(Nolan Lawson)在promises pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html上的文章中给出了“高级错误#4”的解决方案,给出了相同的建议。这是一本好书。
罗伯特

2
这正是bindMonads中的功能。Haskell提供了语法糖(do-notation),使其看起来像异步/等待语法。
zeronone

50

显式传递

与嵌套回调类似,此技术依赖于闭包。但是,链条保持不变-不仅传递最新结果,还为每个步骤传递了一个状态对象。这些状态对象会累积先前操作的结果,并传回以后将再次需要的所有值以及当前任务的结果。

function getExample() {
    return promiseA(…).then(function(resultA) {
        // some processing
        return promiseB(…).then(b => [resultA, b]); // function(b) { return [resultA, b] }
    }).then(function([resultA, resultB]) {
        // more processing
        return // something using both resultA and resultB
    });
}

在这里,那个小箭头b => [resultA, b]是关闭函数,resultA并将两个结果的数组传递给下一步的函数。它使用参数解构语法将其再次分解为单个变量。

在ES6进行销毁之前.spread(),许多Promise库(QBluebirdwhen,…)提供了一种漂亮的辅助方法。它需要一个具有多个参数的函数(每个数组元素一个)用作.spread(function(resultA, resultB) { …

当然,此处所需的关闭可以通过一些辅助功能进一步简化,例如

function addTo(x) {
    // imagine complex `arguments` fiddling or anything that helps usability
    // but you get the idea with this simple one:
    return res => [x, res];
}


return promiseB(…).then(addTo(resultA));

另外,您可以雇用Promise.all为数组产生promise:

function getExample() {
    return promiseA(…).then(function(resultA) {
        // some processing
        return Promise.all([resultA, promiseB(…)]); // resultA will implicitly be wrapped
                                                    // as if passed to Promise.resolve()
    }).then(function([resultA, resultB]) {
        // more processing
        return // something using both resultA and resultB
    });
}

您不仅可以使用数组,还可以使用任意复杂的对象。例如,使用_.extendObject.assign在其他辅助函数中:

function augment(obj, name) {
    return function (res) { var r = Object.assign({}, obj); r[name] = res; return r; };
}

function getExample() {
    return promiseA(…).then(function(resultA) {
        // some processing
        return promiseB(…).then(augment({resultA}, "resultB"));
    }).then(function(obj) {
        // more processing
        return // something using both obj.resultA and obj.resultB
    });
}

尽管此模式保证了扁平链,而显式状态对象可以提高清晰度,但是对于长链而言,它将变得乏味。特别是当您仅偶尔需要状态时,您仍然必须将其传递给每一步。有了这个固定的接口,链中的单个回调就紧密地耦合在一起并且不灵活地进行更改。这使得分解单个步骤变得更加困难,并且回调不能直接从其他模块提供-始终需要将它们包装在关心状态的样板代码中。像上面这样的抽象辅助函数可以减轻一些痛苦,但是它总是存在的。


首先,我认为不Promise.all应该鼓励省略的语法(在ES6中,当解构将替换它并将a切换.spread为a时then,通常会产生意想不到的结果。它将无法正常工作。至于扩充-我不确定为什么需要到使用扩充-添加的东西的承诺原型不是反正延伸ES6承诺一种可接受的方式,这是为了与(当前不支持)的子类来扩展。
本杰明Gruenbaum

@BenjaminGruenbaum:“ 省略语法Promise.all ” 是什么意思?ES6不会破坏此答案中的任何方法。spread将a 转换为解构then也不应该有问题。关于.prototype.augment:我知道有人会注意到它,我只是喜欢探索可能性-将其编辑掉。
Bergi,2015年

通过数组语法我的意思return [x,y]; }).spread(...,而不是return Promise.all([x, y]); }).spread(...它的ES6解构糖交换传播的时候,也不会在这里承诺,区别对待的一切返回数组的一个奇怪的边缘情况不会改变。
本杰明·格林鲍姆

3
这可能是最好的答案。承诺是“功能性反应式编程”的光,这通常是采用的解决方案。例如,BaconJs具有#combineTemplate,可让您将结果组合成一个对象,并沿链条传递
U Avalos

1
@CapiEtheriel答案是在ES6并不像今天这样广泛传播时写的。是的,也许是时候交换例子了
Bergi

35

可变的上下文状态

一个简单的(但不那么优雅,而且容易出错)的解决方案是只使用更高范围的变量(链中的所有回调都可以访问),并在获得它们时将结果值写入它们:

function getExample() {
    var resultA;
    return promiseA(…).then(function(_resultA) {
        resultA = _resultA;
        // some processing
        return promiseB(…);
    }).then(function(resultB) {
        // more processing
        return // something using both resultA and resultB
    });
}

除了使用许多变量之外,还可以使用(最初为空)对象,其结果存储为动态创建的属性。

该解决方案有几个缺点:

  • 可变状态是丑陋的全局变量是邪恶的
  • 这种模式无法跨函数边界工作,对函数进行模块化更加困难,因为它们的声明不能离开共享范围
  • 变量的范围不会阻止对其进行初始化之前对其的访问。这对于可能发生竞争条件的复杂的承诺构造(循环,分支,排他)尤其可能。显式地通过状态,承诺鼓励的声明式设计迫使采用一种更干净的编码样式,可以防止这种情况的发生。
  • 必须正确选择这些共享变量的范围。它必须在已执行函数的本地,以防止多个并行调用之间的争用情况,例如,例如,状态存储在实例上时。

Bluebird库鼓励使用传递的对象,并使用bind()方法将上下文对象分配给Promise链。每个回调函数都可以通过否则无法使用的this关键字来访问它。尽管对象属性比变量更容易出现错别字,但这种模式非常聪明:

function getExample() {
    return promiseA(…)
    .bind({}) // Bluebird only!
    .then(function(resultA) {
        this.resultA = resultA;
        // some processing
        return promiseB(…);
    }).then(function(resultB) {
        // more processing
        return // something using both this.resultA and resultB
    }).bind(); // don't forget to unbind the object if you don't want the
               // caller to access it
}

可以在不支持.bind的promise库中轻松模拟这种方法(尽管有些冗长,并且不能在表达式中使用):

function getExample() {
    var ctx = {};
    return promiseA(…)
    .then(function(resultA) {
        this.resultA = resultA;
        // some processing
        return promiseB(…);
    }.bind(ctx)).then(function(resultB) {
        // more processing
        return // something using both this.resultA and resultB
    }.bind(ctx));
}

.bind()防止内存泄漏是不必要的
Esailija

@Esailija:但是返回的promise是否不包含对上下文对象的引用?好的,当然,垃圾回收将在以后处理;除非从未兑现承诺,否则这不是“泄漏”。
Bergi 2015年

是的,但是承诺也参考了其实现价值和错误原因……但是没有内容参考了承诺,因此没关系
Esailija 2015年

4
当我几乎对序言进行投票时,请将此答案一分为二!我认为“琐碎(但不实用且容易出错)的解决方案”是最干净,最简单的解决方案,因为它比闭包和可变状态更依赖于您接受的自我回答,但更简单。关闭既不是全球性的也不是邪恶的。在这种前提下,反对这种方法的论点对我来说毫无意义。可以给“出色的长期统一承诺链”带来哪些模块化问题?
2015年

2
就像我在上面说的那样,承诺是“功能性反应式编程”的光。这是FRP中的反模式
U Avalos

15

对“可变上下文状态”的苛刻要求较低

使用本地范围的对象来收集承诺链中的中间结果是解决您提出的问题的一种合理方法。考虑以下代码段:

function getExample(){
    //locally scoped
    const results = {};
    return promiseA(paramsA).then(function(resultA){
        results.a = resultA;
        return promiseB(paramsB);
    }).then(function(resultB){
        results.b = resultB;
        return promiseC(paramsC);
    }).then(function(resultC){
        //Resolve with composite of all promises
        return Promise.resolve(results.a + results.b + resultC);
    }).catch(function(error){
        return Promise.reject(error);
    });
}
  • 全局变量不好,因此此解决方案使用局部范围的变量,不会造成任何危害。它只能在函数中访问。
  • 可变状态是丑陋的,但这不会以丑陋的方式改变状态。丑陋的可变状态传统上是指修改函数自变量或全局变量的状态,但是此方法只是修改局部存在范围的变量的状态,该变量仅出于汇总promise结果的目的而存在...一个将死于简单死亡的变量一旦诺言解决。
  • 不会阻止中间承诺访问结果对象的状态,但这不会引入某些可怕的情况,在这种情况下,链中的一个承诺会流氓并破坏您的结果。在承诺的每个步骤中设置值的责任仅限于此功能,并且总体结果将是正确的还是不正确的...它将不会是会在生产后多年出现的一些错误(除非您打算这样做) !)
  • 这不会引入由并行调用引起的竞争条件场景,因为将为getExample函数的每次调用创建一个结果变量的新实例。


谢谢@Bergi,直到您提到它,我才意识到这是一种反模式!
杰伊

这是减轻与promise相关的错误的好方法。我使用的是ES5,不想添加其他库来处理promise。
nilakantha singh deo

8

节点7.4现在支持带有和声标志的异步/等待调用。

尝试这个:

async function getExample(){

  let response = await returnPromise();

  let response2 = await returnPromise2();

  console.log(response, response2)

}

getExample()

并使用以下命令运行文件:

node --harmony-async-await getExample.js

可以简单!


8

这几天,我也遇到了像你这样的问题。最后,我找到了一个很好的解决方案,它简单易读。希望对您有所帮助。

根据如何链接javascript-promises

好的,让我们看一下代码:

const firstPromise = () => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('first promise is completed');
            resolve({data: '123'});
        }, 2000);
    });
};

const secondPromise = (someStuff) => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('second promise is completed');
            resolve({newData: `${someStuff.data} some more data`});
        }, 2000);
    });
};

const thirdPromise = (someStuff) => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('third promise is completed');
            resolve({result: someStuff});
        }, 2000);
    });
};

firstPromise()
    .then(secondPromise)
    .then(thirdPromise)
    .then(data => {
        console.log(data);
    });

4
这并不能真正回答有关如何访问链中先前结果的问题。
Bergi'7

2
每个诺言都可以得到先前的价值,这意味着什么?
yzfdjzwl

1
看一下问题中的代码。目的不是获得所承诺的结果.then,而是获得之前的结果。例如thirdPromise访问的结果firstPromise
Bergi '17

6

另一个答案,使用babel-node版本<6

使用 async - await

npm install -g babel@5.6.14

example.js:

async function getExample(){

  let response = await returnPromise();

  let response2 = await returnPromise2();

  console.log(response, response2)

}

getExample()

然后,运行babel-node example.js并瞧!


1
是的,我在发布我的信息后就这么做了。不过,我将保留它,因为它说明了如何使用ES7实际启动并运行,而不是仅仅说有一天ES7将可用。
安东尼

1
哦,对了,我应该更新我的回答,说这些的“实验”插件已经在这里了。
Bergi

2

我不会在自己的代码中使用此模式,因为我不太喜欢使用全局变量。但是,在紧急情况下它将起作用。

用户是一个承诺的猫鼬模型。

var globalVar = '';

User.findAsync({}).then(function(users){
  globalVar = users;
}).then(function(){
  console.log(globalVar);
});

2
请注意,Mutable上下文状态答案中已经详细说明了这种模式(以及为什么它很丑-我也不是大粉丝)
Bergi 2015年

对于您而言,该模式似乎毫无用处。您根本不需要一个globalVar,只是要做User.findAsync({}).then(function(users){ console.log(users); mongoose.connection.close() });
Bergi 2015年

1
我不需要自己编写代码,但是用户可能需要在第二个函数中运行更多异步代码,然后与原始Promise调用进行交互。但是就像前面提到的,在这种情况下,我将使用生成器。:)
安东尼

2

另一个答案,使用顺序执行程序nsynjs

function getExample(){

  var response1 = returnPromise1().data;

  // promise1 is resolved at this point, '.data' has the result from resolve(result)

  var response2 = returnPromise2().data;

  // promise2 is resolved at this point, '.data' has the result from resolve(result)

  console.log(response, response2);

}

nynjs.run(getExample,{},function(){
    console.log('all done');
})

更新:添加了工作示例

function synchronousCode() {
     var urls=[
         "https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js",
         "https://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js",
         "https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"
     ];
     for(var i=0; i<urls.length; i++) {
         var len=window.fetch(urls[i]).data.text().data.length;
         //             ^                   ^
         //             |                   +- 2-nd promise result
         //             |                      assigned to 'data'
         //             |
         //             +-- 1-st promise result assigned to 'data'
         //
         console.log('URL #'+i+' : '+urls[i]+", length: "+len);
     }
}

nsynjs.run(synchronousCode,{},function(){
    console.log('all done');
})
<script src="https://rawgit.com/amaksr/nsynjs/master/nsynjs.js"></script>



1
function getExample() {
    var retA, retB;
    return promiseA(…).then(function(resultA) {
        retA = resultA;
        // Some processing
        return promiseB(…);
    }).then(function(resultB) {
        // More processing
        //retA is value of promiseA
        return // How do I gain access to resultA here?
    });
}

简单的方法:D


您注意到这个答案了吗?
Bergi

1

我认为您可以使用RSVP的哈希。

如下所示:

    const mainPromise = () => {
        const promise1 = new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log('first promise is completed');
                resolve({data: '123'});
            }, 2000);
        });

        const promise2 = new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log('second promise is completed');
                resolve({data: '456'});
            }, 2000);
        });

        return new RSVP.hash({
              prom1: promise1,
              prom2: promise2
          });

    };


   mainPromise()
    .then(data => {
        console.log(data.prom1);
        console.log(data.prom2);
    });

是的,这Promise.all解决方案相同,只是使用对象而不是数组。
贝尔吉

0

解:

您可以使用“ bind”将中间值显式地放置在任何后续“ then”函数的作用域中。这是一个很好的解决方案,不需要更改Promises的工作方式,只需要一行或两行代码即可传播值,就像已经传播了错误一样。

这是一个完整的示例:

// Get info asynchronously from a server
function pGetServerInfo()
    {
    // then value: "server info"
    } // pGetServerInfo

// Write into a file asynchronously
function pWriteFile(path,string)
    {
    // no then value
    } // pWriteFile

// The heart of the solution: Write formatted info into a log file asynchronously,
// using the pGetServerInfo and pWriteFile operations
function pLogInfo(localInfo)
    {
    var scope={localInfo:localInfo}; // Create an explicit scope object
    var thenFunc=p2.bind(scope); // Create a temporary function with this scope
    return (pGetServerInfo().then(thenFunc)); // Do the next 'then' in the chain
    } // pLogInfo

// Scope of this 'then' function is {localInfo:localInfo}
function p2(serverInfo)
    {
    // Do the final 'then' in the chain: Writes "local info, server info"
    return pWriteFile('log',this.localInfo+','+serverInfo);
    } // p2

可以按以下方式调用此解决方案:

pLogInfo("local info").then().catch(err);

(注意:已经测试了此解决方案的更复杂和完整的版本,但未测试此示例版本,因此可能存在错误。)


这似乎与嵌套(和)闭包答案中的模式相同
Bergi,

看起来确实相似。从那以后,我了解到新的Async / Await语法包括参数的自动绑定,因此所有参数都可用于所有异步函数。我放弃了承诺。
David Spector

async/ await仍表示使用诺言。您可能会放弃的是then带有回调的调用。
Bergi

-1

我了解到的Promise是仅将其用作返回值,尽可能避免引用它们。异步/等待语法对此特别实用。如今,所有最新的浏览器和节点都支持它:https : //caniuse.com/#feat=async-functions,这是一种简单的行为,其代码就像读取同步代码一样,而无需考虑回调...

在我确实需要引用的情况下,一个承诺是在独立/无关的地方进行创建和解决。因此,为了代替“遥远的”承诺,人为的关联,可能还有一个事件侦听器,我更愿意将承诺公开为Deferred,以下代码在有效的es5中实现了它。

/**
 * Promise like object that allows to resolve it promise from outside code. Example:
 *
```
class Api {
  fooReady = new Deferred<Data>()
  private knower() {
    inOtherMoment(data=>{
      this.fooReady.resolve(data)
    })
  }
}
```
 */
var Deferred = /** @class */ (function () {
  function Deferred(callback) {
    var instance = this;
    this.resolve = null;
    this.reject = null;
    this.status = 'pending';
    this.promise = new Promise(function (resolve, reject) {
      instance.resolve = function () { this.status = 'resolved'; resolve.apply(this, arguments); };
      instance.reject = function () { this.status = 'rejected'; reject.apply(this, arguments); };
    });
    if (typeof callback === 'function') {
      callback.call(this, this.resolve, this.reject);
    }
  }
  Deferred.prototype.then = function (resolve) {
    return this.promise.then(resolve);
  };
  Deferred.prototype.catch = function (r) {
    return this.promise.catch(r);
  };
  return Deferred;
}());

转换成我的打字稿项目:

https://github.com/cancerberoSgx/misc-utils-of-mine/blob/2927c2477839f7b36247d054e7e50abe8a41358b/misc-utils-of-mine-generic/src/promise.ts#L31

对于更复杂的情况,我经常使用这些家伙承诺工具,而无需测试和键入依赖项。p-map已经有用了好几次了。我认为他涵盖了大多数用例:

https://github.com/sindresorhus?utf8=%E2%9C%93&tab=repositories&q=promise&type=source&language=


听起来您是在建议可变的上下文状态还是同步检查
Bergi

@bergi第一次我使用这些名称。谢谢。我知道这种由Deferred命名的自我承诺-顺便说一句,实现只是一个带有解决方案的承诺。在承诺创建和解决的责任是独立的情况下,我经常需要这种模式,因此无需为了解决承诺就将它们联系起来。我改编了但不适合您的示例,并使用了一个类,但也许是等效的。
–cerenbero
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.