2016-08-13 5 views
-1

最近非常に興味深い問題が発生しました。背景には、httpリクエストを同時に起動し、各応答の結果を配列で取得したいということです。また、要求のすべての約束が解決されると、。 私は2つの方法で実装しようとしましたが、異なる結果が得られることがありました。Promise.allのスケジュール順はPromise.allでグループ化すると約束します

次のコードスニペット(httpHelper.getはBlueBirdの約束を返します)をご覧ください。 溶液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にプッシュされることを保証します。私は、PromisePromise.allのためにthenがどのようにスケジュールされるのかが原因だと思う。 私の質問は、解決策AでpromisesPromise.thenの約束であるべきではないということです。それではallThenCallBackの機能に達する前に、すべての応答のために関数singleThenCallBackが呼び出されるべきですか?

誰かが私にこの行動の理由を説明してくれることを願っています。ありがとう!

編集

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

あなたは本当に 'forEach' +' push'の代わりに 'map'を使うべきです – Bergi

答えて

1

これはOPの問題については説明しませんが、コメントには適していません。

これは意味をなさない。 solutionAまたはsolutionBの両方に同じ結果が必要です。すべての約束が正常に解決された後にresults.lengthrequestOptions.lengthに等しいか、httpHelper.get(requestOption)の1つ以上が失敗し、Promise.all(promises)も拒否され、resultが返されます。だから、問題はどこにでもあると私は確信しています。その横に

あなたは青い鳥を使用すると、あなたがより明確な方法(あなたがconst Promise = require('bluebird')を使用することを想定して、あなたのコードを書くことができます:あなたは矢印の機能を使用することができES6で

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); 
}); 

はそのように書く:

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()ハンドラが実行されます。これは、元の約束が行われず、.then()ハンドラまで解決されているためです(より高いレベルの約束が解決するまで待たなければならないという連鎖した約束を返すことができるので)呼び出されました。しかし、元の.then()ハンドラは、すべての操作が並行して実行されているため、予測可能な順序で実行されません。つまり、solutionAのresults配列が整列していないことを意味します。あなたがブルーバードを使用している場合は、同様に反復を兼ね備えPromise.map()を使用することができ、

_.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.all()

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

@ david-z - Hey David。あなたはここにいますか?私たちのいくつかは答えを掲示し、私たちはあなたから何も返されていません。 – jfriend00

+0

ご返信ありがとうございますが、ここで問題が発生していると思います。その仕事が内部的にどのように説明されているかを示す有用な文書はありますか?私は何も見つかりませんでした。 –

+0

@DavidZ。 - 「ここで起こっている問題」はどういう意味ですか?そして、あなたはどんなドキュメンテーションを探していますか? – jfriend00

関連する問題