Javascript:如何在前一个函数的final循环中运行一个函数完成?

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

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上的第一篇文章,所以感谢您的耐心。

你正在遭受closuresi ,它已经(可能)已经一直增加到59之前,任何get通话返回并解除其callback。

本质上, 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调用还没有完成, 他们是asynchronous的。 事实上,重要的是要记住,你的函数将第一次get返回之前返回。

  2. i在你通过的callback中get是对variablesi持久引用 ,而不是创buildcallback时的副本,这就是为什么你看到它总是59(数组长度)。

  3. 你的代码通过不声明你的局部variables而成为“隐式全局的恐惧”(Horror of Implicit Globals)的牺牲品。

请参阅评论以了解如何解决此问题:

 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); } }); } } 

虽然实际上,在这种情况下,我们不需要在callback中使用index ,所以我们并不一定需要将调用分离到一个构build函数中。 但它仍然是一个很好的,干净的分离的事情。