我有一个函数,可以进行几次异步调用,这些调用用返回的数据填充同一对象。一旦对象完全填充,我需要对数据做一些事情,并且由于有多个调用,这不是基本的回调/承诺场景。
在这种情况下,是否可以创建承诺?简化代码:
price_options = [] // when this is populated from all the async calls, I need to do stuff with it
sheet_columns = [3,5,7,89]
useServiceAccountAuth(credentials, function(error){ //google docs api
for (var i = 0; i < sheet_columns.length; i++) {
var params = {column_number: sheet_cols[i]}
do_async_call(params, function (e, data) {
data.forEach( function(item) {
price_options.push(item)
})
})
}
})
其他答案对他们来说有很多错误信息。
你应该做的是使用Promise.all()
来聚合所有的承诺。 Promise.all()
采用一个 Promise 数组,并返回一个 Promise,该 Promise 在数组中的所有 Promise 都已解析后解析。
所以现在,你需要创建一个函数来接受每个params
条目,并为它上的数据创建一个 Promise,并将其推送到一个新的数组中。
由于我们使用的是 Promises,让我们去掉代码中的所有其他回调:
// The "functionNameAsync" convention indicates that the function returns Promises.
// This convention was coined by Bluebird's promisifying functions.
// Takes credentials
// Returns a promise that rejects on error, or resolves with nothing on no error.
const useServiceAccountAuthAsync = credentials =>
new Promise((resolve, reject) =>
useServiceAccountAuth(credentials, err => err ? reject(err) : resolve()));
const doCallAsync = params =>
new Promise((resolve, reject) =>
do_async_call(params, (err, data) => err ? reject(err) : resolve(data)));
/* If you opt to use Bluebird, everything above this line can be replaced with:
const useServiceAccountAuthAsync = Promise.promisify(useServiceAcountAuth);
const doCallAsync = Promise.promisify(do_async_call);
it would even be faster than my version above. */
// Now time for the actual data flow:
const sheet_columns = [3,5,7,89]
useServiceAccountAsync()
.then(() => {
const arrayOfAsyncCallPromises = sheet_columns
.map(columnNumber => ({column_number: sheet_cols[columnNumber]}))
.map(doCallAsync);
//.map(param => doCallAsync(param)) equivalent to above
return Promise.all(arrayOfAsyncCallPromises);
})
.then(price_options => {
// use here
})
.catch(err => {
// handle errors here
});
你需要创建一系列承诺。在这里,您可以了解更多信息。
http://bluebirdjs.com/docs/api/promise.all.html
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
你可以这样做:
let results = sheet_columns.map(c => ({column_number: c}))
.map(params => new Promise((resolve, reject) => {
do_async_call(params, (e, data) => {
if(e) {
reject(e);
} else {
resolve(data);
}
})
}))
Promise.all(results).then(arr => Array.prototype.concat.apply([], arr)).then(price_options => doSomething(price_options))
在这里工作 jsbin
使用 promise,请将 do_async_call 函数包装在 promise 返回函数中。
price_options = [];
sheet_columns = [3,5,7,89]
useServiceAccountAuth(credentials, function(error){ //google docs api
var promise_array = [];
for (var i = 0; i < sheet_columns.length; i++){
var params = {column_number: sheet_cols[i]}
var promise = do_async_promise(params);
promise_array.push(promise);
}
Q.all(promise_array).then(function(){
//do your operation with price_options here;
});
})
function do_async_promise(params){
var deferred = Q.defer();
do_async_call(params, function (e, data) {
data.forEach( function(item) {
price_options.push(item);
});
deferred.resolve();
})
return deferred.promise;
}
正如其他研究员所说,Promise.all的使用,我用Promise.all为你写了这个片段,看看。
price_options = [];
sheet_columns = [3,5,7,89];
var promises = [];
useServiceAccountAuth(credentials, function(error){ //google docs api
for (var i = 0; i < sheet_columns.length; i++) {
var params = {column_number: sheet_cols[i]}
// create a new promise and push it to promises array
promises.push(new Promise(function(resolve, reject) {
do_async_call(params, function (e, data) {
resolve(data);
});
}));
}
// now use Promise.all
Promise.all(promises).then(function (args) {
args.forEach(function (data, i) {
data.forEach(function(item) {
price_options.push(item)
});
});
// here do your stuff which you want to do with price_options
});
})