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); } }); } }
你遇到两个(或者可能是三个)问题:
-
在
for
循环之后你不能这么做的原因是调用数据库的get
调用还没有完成, 他们是asynchronous的。 事实上,重要的是要记住,你的函数将在第一次get
返回之前返回。 -
i
在你通过的callback中get
是对variablesi
的持久引用 ,而不是创buildcallback时的副本,这就是为什么你看到它总是59(数组长度)。 -
你的代码通过不声明你的局部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函数中。 但它仍然是一个很好的,干净的分离的事情。