Javascript:如何在上一个函数的最后一个for循环结束后运行一个函数



我正在编写一个Javascript函数,它从CloudDB数据库中提取单词,并将它们放入三个数组中的一个:动词、形容词或名词。一旦所有的单词都到位,最后一个循环运行,我想运行下一个函数。下面是代码:

function verbnoun(array){
verbs = [];
adjectives = [];
nouns = []; 
for (i = 0; i<array.length; i++){
    //console.log(i);  <-- returns 0,1,2,3...57,58 as expected
    my_db.get(array[i], function(err, doc) {
        if (!err){
            if (doc.type == "verb"){
                verbs.push(doc.word);
            }
            else if (doc.type == "adjective"){
                adjectives.push(doc.word);
            }
            else if (doc.type == "noun"){
                nouns.push(doc.word);
            }

        }
        //console.log(i); <-- returns 59,59,59,59,59
        if (i+1 == array.length){
            nextFunction(verbs, adjectives, nouns);
        }       
    });
}

}

但是我不知道如何在最后一个循环后运行下一个函数。如果我尝试在for循环之外运行它,我只会得到空数组。使用if语句在最后一个循环上触发似乎也不起作用,因为for循环中的"i"每次都卡住在59上,而不是从0、1、2、3等开始计数(参见代码中的注释),所以我不能单独指出哪一个是最后一个循环。

这是我在StackExchange上的第一篇文章,所以谢谢你的耐心。

您正在遭受i的关闭,它(可能)在任何get调用返回并触发其回调之前一直增加到59。

本质上,i表示发送请求的数量,而不是成功返回的数量。您需要一个不同的计数器来跟踪该值。

function verbnoun(array) {
  verbs = [];
  adjectives = [];
  nouns = [];
  
  // New counter for completed requests
  var finished = 0;
  for (i = 0; i < array.length; i++) {
    //console.log(i);  <-- returns 1,2,3...57,58,59 as expected
    my_db.get(array[i], function(err, doc) {
      if (!err) {
        if (doc.type == "verb") {
          verbs.push(doc.word);
        } else if (doc.type == "adjective") {
          adjectives.push(doc.word);
        } else if (doc.type == "noun") {
          nouns.push(doc.word);
        }
      }
      //console.log(i); <-- returns 59,59,59,59,59
      if (++finished == array.length) {
        nextFunction(verbs, adjectives, nouns);
      }
    });
  }
}

你遇到了两个(或三个)问题:

  1. 你不能在for循环之后这样做的原因是get对数据库的调用还没有完成;他们是异步的。事实上,重要的是要记住,函数将在第一个get返回之前返回

  2. i在你传递给get的回调中是一个对变量i的持久引用,而不是在创建回调时它的副本,这就是为什么你看到它总是59(数组长度)。

  3. 你的代码正在成为隐式全局变量的恐怖的牺牲品,因为没有声明你的局部变量。

如何处理,请参阅注释:

function verbnoun(array) {
    // Use var to declare your variables
    var verbs = [];
    var adjectives = [];
    var nouns = [];
    // Use a counter to remember how many responses you've had
    var responses = 0;
    // Schedule the calls
    for (var i = 0; i < array.length; i++) {
        // Call a function do do the work, passing in the index
        // for this loop
        doGet(i);
    }
    // Remember, your function returns at this point, before ANY
    // of the callbacks occurs
    // This function does the work
    function doGet(index) {
        // Because we're using `index`, not `i`, we get a value
        // for each call that won't change
        my_db.get(array[index], function(err, doc) {
            if (!err) {
                if (doc.type == "verb") {
                    verbs.push(doc.word);
                } else if (doc.type == "adjective") {
                    adjectives.push(doc.word);
                } else if (doc.type == "noun") {
                    nouns.push(doc.word);
                }
            }
            // Count this response
            ++responses;
            // If we have all of them, we're done
            if (responses == array.length) {
                nextFunction(verbs, adjectives, nouns);
            }
        });
    }
}

虽然实际上,在这个特殊的情况下,我们不需要在回调中使用index,所以我们并不一定需要将调用分离到构建函数中。但它仍然可以很好地将正在发生的事情分开。

最新更新