【问题标题】:How to use promise when variable populated from for loop从for循环填充变量时如何使用promise
【发布时间】:2016-02-29 17:20:56
【问题描述】:

我有一个函数可以进行多个异步调用,这些调用使用返回的数据填充同一个对象。一旦对象完全填充,我需要对数据做一些事情,并且由于有多个调用,这不是基本的回调/承诺场景。

在这种情况下是否可以创建承诺?简化代码:

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 库?
  • @Bergi 你能详细说明一下吗?我正在使用 Q,只是因为我有一些使用它的经验
  • @ilyo:和Q.all一样。获取一系列 promise,然后等待它们。
  • 只需将 Promise 替换为 Q,大多数 Promise 库和原生 js Promise 共享类似的方法名称。在文档中查找 Q.all 以查看其语法
  • 小心for 循环和异步:stackoverflow.com/a/34615512/1225328

标签: javascript node.js promise q


【解决方案1】:

其他答案对他们来说有很多错误信息。

你应该做的是使用Promise.all() 来聚合所有的 Promise。 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
  });

【讨论】:

    【解决方案2】:

    【讨论】:

      【解决方案3】:

      你可以这样做:

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

      Working jsbin here

      【讨论】:

        【解决方案4】:

        如果你想使用 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;
        }
        

        【讨论】:

          【解决方案5】:

          正如其他大佬所说的Promise.all的使用,我用Promise.all给你写了这个sn-p,看看吧。

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

          【讨论】:

            猜你喜欢
            • 2016-08-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-08-14
            • 2020-05-30
            相关资源
            最近更新 更多