Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/wix/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 在Parse.com';异步代码给for循环中的变量提供了错误的值_Javascript_Asynchronous_Parse Platform - Fatal编程技术网

Javascript 在Parse.com';异步代码给for循环中的变量提供了错误的值

Javascript 在Parse.com';异步代码给for循环中的变量提供了错误的值,javascript,asynchronous,parse-platform,Javascript,Asynchronous,Parse Platform,我试图在parse.com上保存不同的食物名称,但不重复。但是,当我运行代码时,数据库由相同的2或3种食物反复组成,而不是200个左右的唯一名称 下面是我的功能。我试着在两个不同的点记录食物的名称,得到了不同的值。第一点给出了食物的正确名称,但第二点只显示亚麻籽松饼或覆盆子派。我认为问题与异步运行的代码有关,但我不确定如何解决这个问题 Parse.Cloud.define("recordFavorite", function(request, response) { var fo

我试图在parse.com上保存不同的食物名称,但不重复。但是,当我运行代码时,数据库由相同的2或3种食物反复组成,而不是200个左右的唯一名称

下面是我的功能。我试着在两个不同的点记录食物的名称,得到了不同的值。第一点给出了食物的正确名称,但第二点只显示亚麻籽松饼或覆盆子派。我认为问题与异步运行的代码有关,但我不确定如何解决这个问题

Parse.Cloud.define("recordFavorite", function(request, response) {

      var foodList = request.params.foodList; //string array of food names
      var Food = Parse.Object.extend("Food");
      var query = new Parse.Query(Food);

      for (i = 0; i < foodList.length; i++ ) {
              var name = foodList[i];
              console.log("before name is " + name);
              var query = new Parse.Query(Food);
              query.exists("name", name);

              query.find({
              success: function(results) {
                if(results.length == 0){
                  var food = new Food();
                  food.set("name", name);
                  food.save(null, {
                    success: function(food) {
                      console.log("saved with name " + name);
                    },
                    error: function(food, error) {
                    }
                  });
                } else {
                  //don't create new food

                }
              },
              error: function(error) {
              }
            });

      }

});
返回所有食物的数组,不过滤包含“name”的对象。(很明显,这可能仍然发生在原始代码中,但我没有注意到。)


关于异步逻辑的问题,我认为你是对的。问题在于,外部循环尽可能快地完成,在执行过程中会触发各种较慢的异步调用,用于食物查找查询。外部循环不会等待,因为当您访问success函数中的“name”时,它被称为“变量提升”,所以它的值将是外部循环中“name”的最新值。因此,当调用success函数时,name的值将移到与您第一次启动exists/save查询序列时不同的位置

下面是一个非常简单的例子:

假设你的食物清单看起来像[松饼],[芝士蛋糕]。当你第一次进入循环时,你的名字是class='Muffin'。您对name='Muffin'发出exists查询,现在是异步进行的。同时,外部循环愉快地继续,设置name='Cheesecake',并触发另一个exists查询。与此同时。第一个exists查询完成,现在可以保存第一个食物了。但是,由于提升,成功函数中的名称的价值现在是“奶酪蛋糕”。因此,它在应该保存“Muffin”的时候保存了“Cheesecake”,然后第二组异步查询完成,而这一组也保存了“Cheesecake”。所以你有两种食物,代表你的两种独特的食物,但都被称为“芝士蛋糕”

这是关于变量提升的经典文章,值得一读:

解决这个问题的一种方法是,在当前食物的所有异步调用完成后,只触发下一个食物的处理。您可以这样做:

Parse.Cloud.define("recordFavorite", function(request, response) {

  var foodList = request.params.foodList; //string array of food names
  var Food = Parse.Object.extend("Food");
  var query = new Parse.Query(Food);

  // Wrap your logic in a function
  function process_food(i) {
      // Are we done?
      if (i == foodList.length) return;

      var name = foodList[i];
      console.log("before name is " + name);
      var query = new Parse.Query(Food);
      query.exists("name", name);

      query.find({
      success: function(results) {
        if(results.length == 0){
          var food = new Food();
          food.set("name", name);
          food.save(null, {
            success: function(food) {
              console.log("saved with name " + name);
              // Move onto the next food, only after all the async operations
              // have completed.
              process_food(i+1)
            },
            error: function(food, error) {
            }
          });
        } else {
          //don't create new food

        }
      },
      error: function(error) {
      }
    });
  }

  // Go! Call the function with the first food.
  process_food(0);
});
(注意,我还没有测试这段代码,所以可能有语法错误)

我以前没见过Parse。。。我看到你的问题,就去看了,觉得很有趣!我将在下一个PHP API项目中记住它。我认为你可以尝试做一些更聪明的事情。例如,您的方法要求每个食物有两个异步调用,一个用于查看它是否存在,另一个用于保存它。对于200种食物,即400个异步调用。不过,parseapi看起来非常有用,我认为它将提供一些工具来帮助您减少这种情况。您可能可以尝试以下方法:

您已经有了要保存的名称字符串数组:

var foodList = request.params.foodList; //string array of food names
说它看起来像[“纸杯蛋糕”、“松饼”、“蛋糕”]

现在构建一个解析查询,以获取服务器上已经存在的所有食物名称。(我不知道怎么做!)。但是你应该得到一个数组,比如说[“纸杯蛋糕”,“芝士蛋糕”]

现在您可以在JavaScript中删除重复项。这里会有一些关于StackOverflow的好问题来帮助解决这个问题!结果将是“纸杯蛋糕”是重复的,因此我们只剩下数组[“Muffins”,“Cake”]

现在,在Parse中,您可以批处理一些操作:

因此,您的目标是通过一个API调用保存这个[“松饼”、“蛋糕”]数组


这种方法可以很好地根据食物的数量进行扩展,因此即使有200种食物,您也应该能够在一个查询中完成,并且每50种食物一次批量更新(从解析文档中,我认为50是一个批量限制),因此您最多需要5个API调用。

我相信这()是您正在寻找的解决方案。您需要利用承诺来强制同步。

不确定它们是如何实现的,但不会让云线程长时间处于繁忙状态。如果有20个用户同时调用此函数,那么获得响应可能会有巨大的延迟?
Parse.Cloud.define("recordFavorite", function(request, response) {

  var foodList = request.params.foodList; //string array of food names
  var Food = Parse.Object.extend("Food");
  var query = new Parse.Query(Food);

  // Wrap your logic in a function
  function process_food(i) {
      // Are we done?
      if (i == foodList.length) return;

      var name = foodList[i];
      console.log("before name is " + name);
      var query = new Parse.Query(Food);
      query.exists("name", name);

      query.find({
      success: function(results) {
        if(results.length == 0){
          var food = new Food();
          food.set("name", name);
          food.save(null, {
            success: function(food) {
              console.log("saved with name " + name);
              // Move onto the next food, only after all the async operations
              // have completed.
              process_food(i+1)
            },
            error: function(food, error) {
            }
          });
        } else {
          //don't create new food

        }
      },
      error: function(error) {
      }
    });
  }

  // Go! Call the function with the first food.
  process_food(0);
});
var foodList = request.params.foodList; //string array of food names