Javascript 在for循环中解析查询(回调)

Javascript 在for循环中解析查询(回调),javascript,callback,parse-platform,Javascript,Callback,Parse Platform,这里是javascript新手,所以回调在我脑子里还是有点不确定 我试图做的是:给定一个“菜单”,它是objectId的数组,查询对应于该objectId的每个foodItem,获取其投票,将其放入最小堆(以确定前5项),然后返回前5项 最后我的堆是空的,因为我意识到JavaScript是异步的,当我试图获取堆数据时,回调可能不一定完成 如果只是一个调用,我只会嵌套回调,但由于这是一个循环,我不确定该怎么做 function getTopFoods(menu, heap, callback) {

这里是javascript新手,所以回调在我脑子里还是有点不确定

我试图做的是:给定一个“菜单”,它是objectId的数组,查询对应于该objectId的每个foodItem,获取其投票,将其放入最小堆(以确定前5项),然后返回前5项

最后我的堆是空的,因为我意识到JavaScript是异步的,当我试图获取堆数据时,回调可能不一定完成

如果只是一个调用,我只会嵌套回调,但由于这是一个循环,我不确定该怎么做

function getTopFoods(menu, heap, callback) {
//go through each objectId, get its foodItem and then its votes, then heap it
    console.log("got to TopFoods");
        for (var i = 0; i < menu.length; i++) {
            var foodID = menu[i];
            var FoodItem = Parse.Object.extend("FoodItem");
            var foodQuery = new Parse.Query(FoodItem);
            foodQuery.equalTo("objectId", foodID);
            //get corresponding foodItem
            foodQuery.find({
                success: function(foodResult) {
                    //got specific food Item
                    var votes = foodResult.get("votes");
                    console.log("votes: " + votes);
                    if (heap.length < 5) {
                        heap.queue(foodResult);
                    } else {
                        if (votes > heap.peek().get("votes")) {
                            heap.dequeue();
                            heap.queue(foodResult);
                        }
                    }
                }, 
                error: function(error) {
                    console.log("Food error: " + error.code + " " + error.message);
                }
            }); 
        }
        var topFoods = [];
        for (var i = 0; i < 5; i++) {
            topFoods[i] = heap.dequeue();
        }
        callback(topFoods);
}
函数getTopFoods(菜单、堆、回调){ //检查每个objectId,获取其foodItem,然后获取其投票,然后将其堆起来 console.log(“转到TopFoods”); 对于(变量i=0;iheap.peek().get(“投票”)){ heap.dequeue(); 队列(foodResult); } } }, 错误:函数(错误){ 日志(“食物错误:+error.code+”+error.message); } }); } var-topFoods=[]; 对于(变量i=0;i<5;i++){ topFoods[i]=heap.dequeue(); } 召回(topFoods); }
最简单的方法是使用承诺;在这个阶段,这涉及到使用一个库(在ES6中使用JavaScript)。如果你想要一个低技术的解决方案,只需计算一下:

var waitingCount = menu.length;
for (....) {
  ...
  success: function(foodResult) {
    ...
    if (!--waitingCount) {
      callback(topFive(heap));
    }
  },
  error: function(error) {
    --waitingCount;
    ...
  }
  ...
}
这只是基本的想法。如果您还减少失败响应上的计数器,这将是一件好事,因为这样一次失败就会让您挂起

编辑:呃,显然,检查需要转到
success
的底部,而不是我的代码片段前面指出的顶部,否则您将错过最后一个元素。我还加入了错误案例

EDIT2:正如eth3lbert所指出的,parse.com API也支持承诺(我不使用parse.com,所以…谢谢你的提示)。在这种情况下,您可以这样做:

var promises = [];
for (....) {
  var promise = foodQuery.find({
    ...
  });
  promises.push(promise);
});
Parse.Promise.when(promises).then(function()) {
  callback(topFive(heap));
}

同意,解析javascript sdk支持承诺,您应该试一试。相关问题:循环中的每个查询都需要调用response.success()或response.error()(但我显然不希望过早调用它)。承诺是最好的处理方式吗?承诺是最干净的方式:它们比自己记账更清晰。不过,它们在引擎盖下的表现并没有太大的不同。我也承诺了解决方案。。。