【问题标题】:Javascript: How to run a function after final for loop in previous function is finished?Javascript:如何在上一个函数的最终 for 循环完成后运行一个函数?
【发布时间】:2015-05-19 16:52:15
【问题描述】:

我正在编写一个 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 上的第一篇文章,感谢您的耐心等待。

【问题讨论】:

标签: javascript node.js for-loop


【解决方案1】:

您正遭受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);
      }
    });
  }
}

【讨论】:

  • “你正遭受 i 的关闭,它(可能)一直增加到 59” 没有“可能”。
  • 完美。感谢您的快速回答!
  • @T.J.Crowder 我想在一个异常线程的运行时,回调可能会在i 一直到 59 之前触发。
  • @ssube:NodeJS 所基于的引擎 V8 的行为并非如此。它使用单线程,就像大多数(但不是全部)JavaScript 引擎一样。
  • @PaulBischoff 虽然这应该可以解决您的问题,但您可能想看看 T.J.Crowder 在他的回答中提出的其他一些建议。您还有其他一些挥之不去的问题。
【解决方案2】:

您在那里遇到了两个(或可能三个)问题:

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

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

  3. 您的代码因未声明局部变量而成为The Horror of Implicit Globals 的牺牲品。

请参阅 cmets 了解如何解决它:

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,因此我们绝对不需要将调用分离到构建器函数中。但它仍然可以很好地、干净地分离正在发生的事情。

【讨论】:

  • 感谢您的详细解答。将来会尝试结合有关局部变量的更好做法。
  • @PaulBischoff:不用担心。您可以通过在 JS 文件顶部添加 "use strict"; 来强制执行操作,这会将 The Horror of Implicit Globals 变成一个不错的、易于调试的 ReferenceError。 :-)
猜你喜欢
  • 2011-05-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-18
  • 1970-01-01
  • 2015-12-22
相关资源
最近更新 更多