解释在 Parse 的 for 循环中执行 find 函数背后的逻辑

Explain the logic behind the execution of find function inisde for loop in Parse

下面是代码:

function f1() {
  for (var i = 0; i < arr.length; i++) {
    var query = new Parse.Query("Group");
    query.equalTo("parent", arr[i]);
    var position = pos[i];
    alert("pos[i] = " + pos[i] + " position = " + position);
    query.find({
      success: function(users) {
        if (users.length === 0) {
          alert("in if");
        } else {
          alert("in else");
        }
      }
    });
  }
}

基本上,Group 是 Parse 类,arr 包含 Class Parse.User 的对象,pos 是存储整数的数组 现在包含 2 个整数:8、15 并且 arr 包含两个值对于 i = 0 users.length != 0 和对于 i = 1,users.length = 0。所以基本上,当这个函数被调用时,我想要的输出是:

pos[i] = 8 position = 8
in else
pos[i] = 15 position = 15
in if

但实际上,我明白了:

pos[i] = 8 position = 8
pos[i] = 15 position = 15      // I don't know why i am getting this, it is irritating me
in else
pos[i] = 15 position = 15
in if

我已经在互联网和 google 上搜索过这个问题,但找不到更好的解决方案。那么如何得到想要的输出呢?

注意:切勿使用 alert 进行调试,当事情发生时,您会被它所产生的影响所误导。几乎总是,您想使用浏览器内置的调试器。在连时间都弄乱的情况下,通过 console.log.

记录事情

但这里的主要问题是 query.find 调用的工作是 异步的 ,它稍后会在循环完成后调用 success 函数。

如果您想知道找到了什么位置等,您可以将该信息绑定到您的 success 回调并让它输出:

    var position = pos[i];
    query.find({
        // Note first arg v
        success: function(pos, users) {
            if (users.length === 0) {
                console.log("in if, pos = " + pos);  
            } else {
                console.log("in else, pos = " + pos);
            }
        }.bind(null, position) // *** Note bind
    });

Function#bind returns 一个新的 "bound" 函数,当被调用时,将调用具有给定 this 值的原始函数(上面未使用,因此初始null),然后传递给 bind 的任何参数,然后传递给绑定函数的参数。

这可能有点难以理解,所以这里有一个更简单的例子:

function foo(a, b) {
  snippet.log("a = " + a + ", b = " + b);
}
var f = foo.bind(null, 'one');
f('two'); // Shows a = one, b = two
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>


如果你想按照严格的顺序执行它们,你必须等待一个调用完成才能开始下一个调用:

function f1() {
    var i = 0;

    doOne();

    function doOne() {
        var query = new Parse.Query("Group");
        var position = pos[i];
        query.equalTo("parent", arr[i]);
        query.find({
          success: function(users) {
            if (users.length === 0) {
                alert("in if");
            } else {
                alert("in else");
            }
            if (++i < arr.length) {
                doOne();
            }
          }
        });
    }
}

考虑使用 Promise.when() 如下:

    var queries = [];

    for (var i = 0; i < arr.length; i++) {   
        var query = new Parse.Query("Group");
        query.equalTo("parent", arr[i]);
        var position = pos[i];
        alert("pos[i] = " + pos[i] + " position = " + position);
        queries.push(query.find());
    }
    Parse.Promise.when(queries).then(function() {
        var users = Array.prototype.slice.call(arguments);
        // users will contain the results of each query in corresponding positions
    });

想法是 find() returns 一个完成异步查找的承诺,而 Promise.when() returns 一个在所有承诺传递给它时实现的承诺已完成。