这与How do I access previous promise results in a .then() chain?
类似,但不完全相同我遇到的情况是我并行发出两个异步请求,然后是第三个异步请求,这取决于前两个的成功,最后将第二个异步请求的结果传递给函数回调。
截至目前,我了解如何以两种方式执行此操作(为简洁省略了.catch语句和函数签名):
使用范围闭包(我当前的实现)
var foo;
Promise.join(promiseA, promiseB, function(resultsA, resultsB) {
foo = resultsB;
return promiseC;
})
.then(function() {
// foo is accessible here
callback(null, foo);
});
使用Promise.bind,但必须使用Promise.map而不是Promise.join
var targetIndex = 1;
Promise.resolve(promises)
.bind({})
.map(function(response, index) {
if (index === targetIndex) {
this.foo = response;
}
})
.then(function() {
return promiseC;
})
.then(function() {
// this.foo is accessible here
callback(null, this.foo);
});
正如你所知,选项2相当丑陋,因为我必须手动检查mapper的index参数是否与我关心的promise结果的索引相匹配。选项1使用范围关闭,我理解在大多数情况下这是不可取的(但在这一点上似乎是我最好的选择)。
我真正想做的是:
Promise.bind({})
.join(promiseA, promiseB, function(resultsA, resultsB) {
this.foo = resultsB;
return promiseC;
})
.then(function() {
// I WISH this.foo WAS ACCESSIBLE HERE!
callback(null, this.foo);
});
我有没有办法利用Promise.join而不是Promise.map来避免在这种情况下使用范围闭包?
答案 0 :(得分:1)
你有一个有趣的用例,因为Promise需要在链中多个步骤的承诺的结果。对于这样一个“落后”的问题,我建议采用“后向”解决方案;在resultB
之后将promiseC
添加回链中:
Promise.join(promiseA, promiseB, function(resultA, resultB) {
return promiseC.then(function() {
return resultB;
});
})
.then(function(resultB) {
callback(null, resultB);
});
理想情况下,promiseC
应该会产生resultB
,但现在总是可以的。
编辑:请注意,我没有故意使用嵌套的promises。匿名函数只用于传递值,而不是执行逻辑。这种方法做了同样的事情:
...
return promiseC.then(function() {
callback(null, resultB); // really not what you should be doing
});
但不鼓励,因为它增加了一层嵌套逻辑,破坏了链接的设计原则。
编辑2:这可以使用绑定闭包来实现,如:
Promise.join(promiseA, promiseB).bind({})
.then(function(resultA, resultB) {
this.resultB = resultB;
return promiseC;
})
.then(function(resultC) {
callback(null, this.resultB);
});
答案 1 :(得分:0)
Node支持生成器,让我们利用Promise.coroutine
充分利用Bluebird的能力:
const yourFunciton = Promise.coroutine(function*(){
// obtain other promises
const a = yield getPromiseA(); // function that returns promiseA
const b = yield getPromiseB(); // function that returns promiseB
const c = yield calculatePromiseC(a, b);
return b; // or whatever value you want to return, or callback with
});
// call yourFunction, it returns a promise for the completion
问题是,通过使用coroutines和modern NodeJS,我们能够完全逃避嵌套和链接,并且可以以直接的同步方式编写异步代码。我们不必进行任何链接或嵌套作用域,因为所有内容都在同一范围内。
答案 2 :(得分:0)
这与How do I access previous promise results in a
类似,但不完全相同.then()
chain?
我认为它完全一样。只需注意您的模式Promise.join
Promise.join(promiseA, promiseB, function(resultsA, resultsB) {
return promiseC;
}).then(function(resultsC) {
// how to get A or B here?
})
相当于" desugared"代码
Promise.all([promiseA, promiseB])
.then(function([resultsA, resultsB]) { // ES6 destructuring syntax
return promiseC;
}).then(function(resultsC) {
// how to get A or B here?
})
鉴于此,我们可以一对一地应用所有解决方案。
嵌套闭包很容易,也比你的方法更好:
Promise.join(promiseA, promiseB, function(resultsA, resultsB) {
return promiseC
.then(function() {
return resultsB;
});
}).then(callback.bind(null, null), callback);
打破链条意味着您只需使用Promise.join
两次:
var promiseC_ = Promise.join(promiseA, promiseB, function(resultsA, resultsB) {
return promiseC
});
Promise.join(promiseC_, promiseB).then(function(_, resultsB) {
return resultsB;
}).then(callback.bind(null, null), callback);
async/await
是未来,如果你使用转换器,你应该去做它:
(async function() {
var [resultsA, resultsB] = await Promise.all([promiseA, promiseB]);
var resultsC = await promiseC;
return resultsB;
}()).then(callback.bind(null, null), callback);
但是如果你不想在ES6中使用转换器,那么你已经可以将Bluebird与发电机一起使用了:
Promise.coroutine(function* () {
var [resultsA, resultsB] = yield Promise.all([promiseA, promiseB]);
var resultsC = yield promiseC;
return resultsB;
})().then(callback.bind(null, null), callback);