2016-08-13 88 views
-1

时承诺最近我遇到了一个非常有趣的问题。背景是我想同时激发一堆http请求,并将每个响应的结果捕获到一个数组中。而且,当所有请求的承诺都解决了,。 我尝试了两种方式来实现它,但有时会得到不同的结果。Promise.Then的调度顺序Promise.all

请看下面的代码片段(httpHelper.get刚刚返回蓝鸟承诺)。 溶液A:

function solutionA() { 
    var requestOptions = [...]; // an array of request options 
    var promises = []; 
    var results = []; 
    _.forEach(requestOptions, function(requestOption){ 
    var promise = httpHelper.get(requestOption).then(function singleThenCallBack(response){ 
      //Using this solution, sometimes this code won't execute from some response, I guess it's because the Promise.all.then gets executed before this then. 
      results.push(response.body.result); 
    }); 
    promises.push(promise); 
    }); 
    return Promise.all(promises).then(function allThenCallBack(){ 
    return results; 
    }); 
} 

溶液B

function solutionB() { 
    var requestOptions = [...]; // an array of request options 
    var promises = []; 
    var results = []; 
    _.forEach(requestOptions, function singleThenCallBack(requestOption){ 
    var promise = httpHelper.get(requestOption); 
    promises.push(promise); 
    }); 
    return Promise.all(promises).then(function allThenCallBack(responses){ 
    _.forEach(responses, function(response){ 
     results.push(response.body.result); 
    }); 
    return results; 
    }); 
} 

因此,使用溶液A的问题是,有时singleThenCallBack功能将不调用一些响应,所以results不包含我应得到的每个结果。 解决方案B始终确保将所有结果推入数组results。我想原因是计划如何thenPromisePromise.all。 我的问题是,A液中,不应该promisesPromise.then S的承诺,这将确保singleThenCallBack功能适用于所有的反应应该被称为达到allThenCallBack功能之前?

希望有人可以解释这种行为对我的原因。谢谢!

编辑: 所以我试图运行一些代码来证明的承诺与下面的代码链接:

var Promise = require("bluebird"); 

var promises = []; 

var promise1 = new Promise(function(resolve, reject){ 
    setTimeout(function() { 
     resolve(1); 
    }, 5000); 
}); 

var thenPromise1 = promise1.then(function(value){ 
    console.log("********* resolved promise1 *********: " + value); 
    console.log(promise1); 
    return 0.1; 
}, console.log("*****This means then function is called synchronously.")); 

promises.push(thenPromise1); 

thenPromise1.then(function(value){ 
    console.log("********* resolved thenPromise1 *********: " + value); 
    console.log(thenPromise1); 
}); 

var allPromise = Promise.all(promises); 

allPromise.then(function(value){ 
    console.log("********* resolved allPromise *********: " + value); 
    console.log(allPromise); 
}); 

console.log("********* promise1 *********"); 
console.log(promise1); 
console.log("********* thenPromise1 *********"); 
console.log(thenPromise1); 
console.log("********* allPromise *********"); 
console.log(allPromise); 

console.log("***********code end*************"); 

,输出是:

*****This means then function is called synchronously. 
********* promise1 ********* 
{ _bitField: 1, 
    _fulfillmentHandler0: [Function], 
    _rejectionHandler0: undefined, 
    _promise0: 
    { '2': 0, 
    '3': 
     { _promise: [Object], 
     _values: [Object], 
     _length: 1, 
     _totalResolved: 0 }, 
    _bitField: 2, 
    _fulfillmentHandler0: [Function], 
    _rejectionHandler0: undefined, 
    _promise0: 
     { _bitField: 0, 
     _fulfillmentHandler0: undefined, 
     _rejectionHandler0: undefined, 
     _promise0: undefined, 
     _receiver0: undefined, 
     _trace: [Object] }, 
    _receiver0: undefined, 
    _trace: { [Error] _parent: undefined, _promisesCreated: 0, _length: 1 } }, 
    _receiver0: undefined, 
    _trace: { [Error] _parent: undefined, _promisesCreated: 0, _length: 1 } } 
********* thenPromise1 ********* 
{ '2': 0, 
    '3': 
    { _promise: 
     { _bitField: 134217729, 
     _fulfillmentHandler0: [Function], 
     _rejectionHandler0: undefined, 
     _promise0: [Object], 
     _receiver0: undefined }, 
    _values: [ [Circular] ], 
    _length: 1, 
    _totalResolved: 0 }, 
    _bitField: 2, 
    _fulfillmentHandler0: [Function], 
    _rejectionHandler0: undefined, 
    _promise0: 
    { _bitField: 0, 
    _fulfillmentHandler0: undefined, 
    _rejectionHandler0: undefined, 
    _promise0: undefined, 
    _receiver0: undefined, 
    _trace: { [Error] _parent: undefined, _promisesCreated: 0, _length: 1 } }, 
    _receiver0: undefined, 
    _trace: { [Error] _parent: undefined, _promisesCreated: 0, _length: 1 } } 
********* allPromise ********* 
{ _bitField: 134217729, 
    _fulfillmentHandler0: [Function], 
    _rejectionHandler0: undefined, 
    _promise0: 
    { _bitField: 0, 
    _fulfillmentHandler0: undefined, 
    _rejectionHandler0: undefined, 
    _promise0: undefined, 
    _receiver0: undefined, 
    _trace: { [Error] _parent: undefined, _promisesCreated: 0, _length: 1 } }, 
    _receiver0: undefined } 
***********code end************* 
********* resolved promise1 *********: 1 
{ _bitField: 33554433, 
    _fulfillmentHandler0: [Function], 
    _rejectionHandler0: 1, 
    _promise0: undefined, 
    _receiver0: undefined, 
    _trace: { [Error] _parent: undefined, _promisesCreated: 0, _length: 1 } } 
********* resolved thenPromise1 *********: 0.1 
{ '2': 0, 
    '3': 
    { _promise: 
     { _bitField: 134217729, 
     _fulfillmentHandler0: [Function], 
     _rejectionHandler0: undefined, 
     _promise0: [Object], 
     _receiver0: undefined }, 
    _values: [ [Circular] ], 
    _length: 1, 
    _totalResolved: 0 }, 
    _bitField: 33554434, 
    _fulfillmentHandler0: [Function], 
    _rejectionHandler0: 0.1, 
    _promise0: undefined, 
    _receiver0: undefined, 
    _trace: { [Error] _parent: undefined, _promisesCreated: 0, _length: 1 } } 
********* resolved allPromise *********: 0.1 
{ _bitField: 167772161, 
    _fulfillmentHandler0: [Function], 
    _rejectionHandler0: [ 0.1 ], 
    _promise0: undefined, 
    _receiver0: undefined } 

在输出中,thenPromise1对象具有_promise0,这是由thenPromise1.then(...)创建的承诺。而'3'后的承诺目标是,通过Promise.all(...),这意味着thenPromise1后,这一承诺始终链接创建的承诺。 所以我认为这个问题是无效的,其他部分有问题。

+0

你在哪里检查代码中'results'的数量? –

+0

这里没有显示,它是SolutionA/B函数的调用者。 –

+0

你真的应该使用'map'而不是'forEach' +'push' – Bergi

回答

1

这并不能说明OP的问题,但我不适合评论。

这是没有意义的。 solutionAsolutionB应该具有相同的结果。或者所有Promise都成功解析,然后results.length必须等于requestOptions.lengthhttpHelper.get(requestOption)中的一个或多个失败,然后Promise.all(promises)也将被拒绝,并且不会返回result。所以我很确定这个问题在其他地方。

除此之外,当你使用的蓝鸟你可以在一个更清晰的方式编写代码(假设你使用const Promise = require('bluebird')

function solution() { 
    var requestOptions = [...]; // an array of request options 

    return Promise.all(requestOptions) // pass all request options 
    .map(function(requestOption) { // for each option create a request and return its promise 
     return httpHelper.get(requestOption); 
    }) 
    .map(function(response) { // for each response return the response.body.result 
     return response.body.result; 
    }); // now the promise resolves to an array containing the just the response.body.result 
} 

solutionA() 
.then(function(result) { 
    console.dir(result); 
}); 

随着ES6你可以使用箭头功能写这样的说法:

function solution() { 
    var requestOptions = [...]; // an array of request options 

    return Promise.all(requestOptions) // pass all request options 
    .map(requestOption => httpHelper.get(requestOption)) 
    .map(response => response.body.result); 
} 
+0

感谢您的回答。这正是我认为它应该起作用的原因,当它没有时,这让我感到非常困惑。 –

0

.then().then()你的初始承诺将执行在Promise.all().then()处理程序将执行之前,这是因为原始承诺没有完成并解决,直到.then()处理程序(因为它可能会返回一个承诺,即更高级别的承诺在它解决之前必须等待)。但是,那些原始的.then()处理程序将不会以可预测的顺序执行,因为所有操作都是并行运行的,这意味着solutionA中的results数组不正确。

我建议你只是改变了当初的诺言这样的结果:

_.forEach(requestOptions, function(requestOption){ 
    var promise = httpHelper.get(requestOption).then(function singleThenCallBack(response){ 
     // change resolved value to be the body.result 
     return response.body.result; 
    }); 
    promises.push(promise); 
    }); 
    return Promise.all(promises); 

但是,如果你正在使用蓝鸟,你不妨使用Promise.map()与结合迭代Promise.all()

return Promise.map(requestOptions, function(item) { 
    return httpHelper.get(item).then(function(response) { 
     return response.body.result; 
    }); 
}); 
+0

@ david-z - 嘿大卫。你在这里?我们中的一些人发布了答案,我们还没有收到任何回复。 – jfriend00

+0

感谢您的回复,但我相信问题在这里发生。有没有任何有用的文档解释内部工作的方式?我没有找到任何。 –

+0

@DavidZ。 - 你的意思是“这里发生的问题”是什么?而且,你在找什么文件? – jfriend00