【问题标题】:javascript - have promises call at end of for loopjavascript - 在 for 循环结束时调用 promise
【发布时间】:2014-12-25 08:58:20
【问题描述】:

我有这段代码,我想让代码等到名为 prom 的异步查询完成后再重新启动第一个 for 循环。因此数组将在再次开始第一个 for 循环之前被重置。

items = [];
var promises = [];
    for (var i = 0; i < userArray.length; i++) {

        items.length = 0;
        for (var i2 = 0; i2 < test.length; i2++) {

            var UserFavourite = Parse.Object.extend("UserFavourite");
            var queryUserFav = new Parse.Query(UserFavourite);
            queryUserFav.equalTo('item', test[i2].get('item'));
            queryUserFav.equalTo('school', test[i2].get('school'));
            queryUserFav.equalTo('user1', userArray[i])
            var prom = queryUserFav.find().then(function(res) {


                    for (var i3 = 0; i3 < res.length; i3++){
                        var item = res[i3];
                        var itemName = item.get('item');
                        items.push(itemName);
                        console.log(items)

                    }
                    return items;


            });
            promises.push(prom);

        }
        //return Parse.Promise.when.apply(Parse.Promise, promises); I have tried it here but
        // this just stops the first for loop after its first loop

    }
    return Parse.Promise.when.apply(Parse.Promise, promises);

【问题讨论】:

    标签: javascript arrays parse-platform cloud promise


    【解决方案1】:

    你想要做的是有一个承诺链,一个用于数组中的每个项目。

    如果 javascript 有一个等价于 .NET 的 await 关键字就好了,你可以去哪里

     await Parse.Promise.when(promises)
    

    然后它允许运行承诺代码,然后返回运行await 之后的任何代码。但是 Javascript 并没有给我们这个。


    另一种方法是维护一个index 变量。处理完每组查询后,递增 index 变量并处理下一组值。

     function parseForUser(user) {
          var promises = [];
          for (var i2 = 0; i2 < test.length; i2++) {
            var items = [];
            var UserFavourite = Parse.Object.extend("UserFavourite");
            var queryUserFav = new Parse.Query(UserFavourite);
            queryUserFav.equalTo('item', test[i2].get('item'));
            queryUserFav.equalTo('school', test[i2].get('school'));
            queryUserFav.equalTo('user1', user)
            var prom = queryUserFav.find().then(function(res) {
                    for (var i3 = 0; i3 < res.length; i3++){
                        var item = res[i3];
                        var itemName = item.get('item');
                        items.push(itemName);
                        console.log(items)
    
                    }
                    return items;
            });
            promises.push(prom);
          }
          return Parse.Promise.when(promises);
    
     }
    
    
     function parseUserArray(userArray) {
         var returnPromise = new Parse.Promise(); // Do you have to call it via new? 
                                                  //The documentation isn't clear.
         var index = 0;
         var doNext = function() {
             if(index < userArray.length) {
                var promise = parseForUser(userArray[index++]);
                promise.done(doNext);
             } else {
                 returnPromise.resolve(); 
             }
         }
         doNext();
         return returnPromise;
     }
    
     var parseUserArrayPromise = parseUserArray(userArray);
    

    【讨论】:

    • 我的查询依赖于变量 i 如果我没有声明,我怎么称呼它?
    • @spenf - 您的查询实际上并不依赖于变量i,它依赖于userArray[i] 的用户。请注意,此代码parseForUser 将用户对象作为参数。
    • 好吧,我只是对如何输入查询代码有点困惑?
    • @spenf - 我现在已将其包含在代码示例中。请注意,我没有对此进行测试,它只是为您提供解决问题的方法。
    • 在您的解决方案中描述一般想法的一些文字将使您的答案成为更好的答案。
    【解决方案2】:

    FWIW ...

    此解决方案与@AndrewShepherd 的不同之处主要在于这里我们双重利用了asyncProcessUser() 返回的承诺。

    • 首先是流控——内循环的异步排序
    • 其次,用于提供结果数组,从中构建最终结果数组,从而避免需要外部 promises 数组。
    function parseUserArray(userArray, test) {
    
        // This function is the original inner for() loop, now expressed as a .map(), 
        // (plus peripheral wrapping and chaining).
        // It asynchronously processes a single user against all test items,
        // and returns a promise of an array of results.
        // The promise resolves when all the individual .finds complete.
        function asyncProcessUser(user) {
            return Parse.Promise.when(test.map(function(dataItem) {
                return (new Parse.Query(Parse.Object.extend("UserFavourite")))
                    .equalTo('item', dataItem.get('item'))
                    .equalTo('school', dataItem.get('school'))
                    .equalTo('user1', user)
                    .find().then(function(res) {
                        return res.map(function(r) {
                            return r.get('item');
                        });
                    });
            })).then(function() {
                return Array.prototype.slice.apply(arguments).reduce(function(arr, arr_) {
                    return arr.concat(arr_);
                }, []);
            });
        }
    
        // This is the original outer for() loop, now expressed as a .reduce(), which is 
        // a common pattern for performing a series of async tasks (ie what was the inner loop).
        // Here, `userArray.reduce(...)` returns a promise of an array of 
        // the objects returned by `r.get('item')` above.
        return userArray.reduce( function(p, user) {
            return p.then(function(arr) {
                return asyncProcessUser(user).then(function(arr_) {
                    return arr.concat(arr_);
                });
            });
        }, Parse.Promise.as([]) );//† "returns a new promise that is resolved with a given value".
    }
    

    †:Documentation for Parse.Promise.as()

    没有cmets,还是挺简洁的。

    这个概念被证明了here。不用担心演示使用 jQuery 承诺,重要的是概念。

    【讨论】:

      【解决方案3】:

      使用这个

      function parseForUser(user) {
            var promises = [];
            for (var i2 = 0; i2 < test.length; i2++) {
              var items = [];
              var UserFavourite = Parse.Object.extend("UserFavourite");
              var queryUserFav = new Parse.Query(UserFavourite);
              queryUserFav.equalTo('item', test[i2].get('item'));
              queryUserFav.equalTo('school', test[i2].get('school'));
              queryUserFav.equalTo('user1', user)
              var prom = queryUserFav.find().then(function(res) {
                      for (var i3 = 0; i3 < res.length; i3++){
                          var item = res[i3];
                          var itemName = item.get('item');
                          items.push(itemName);
                          console.log(items)
      
                      }
                      return items;
              });
              promises.push(prom);
            }
            return Parse.Promise.when(promises);
      
       }
      
      
       function parseUserArray(userArray) {
           var returnPromise = new Parse.Promise(); // Do you have to call it via new? 
                                                    //The documentation isn't clear.
           var index = 0;
           var doNext = function() {
               if(index < userArray.length) {
                  var promise = parseForUser(userArray[index++]);
                  promise.done(doNext);
               } else {
                   returnPromise.resolve(); 
               }
           }
           doNext();
           return returnPromise;
       }
      

      复制粘贴即可

      【讨论】:

        猜你喜欢
        • 2019-03-25
        • 1970-01-01
        • 1970-01-01
        • 2017-10-20
        • 1970-01-01
        • 1970-01-01
        • 2022-12-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多