在Node js中完成for循环时调用函数
function inboxUsers(){ for (var i=0; i<uniqueArray.length; i++){ var getUsername = 'SELECT userName FROM users WHERE userId = ' + uniqueArray[i]; db.query(getUsername, function(err, results) { if (err) { console.log('Error in database'); throw err; } for(var i in results){ console.log('single',results[i].userName); inboxUserList.push(results[i].userName); } }); } sample(); } function sample(){ console.log('same function'); }
这是我的控制台输出。
same function single user1 single user2 single user3
在这个代码中,我在for循环之后调用了函数sample() ,但在循环结束之前它调用了sample()函数 。
我想在for循环结束时调用sample()函数。 我是一个初学者的stackoverflow,如果我有错误,请道歉。 谢谢
你对db.query
调用是asynchronous的。 这意味着什么:
-
对
db.query(...)
的调用立即返回,不返回任何内容。 -
而不是分配一个返回值给一个variables(
var results = db.query(...)
),你传入一个callback函数作为参数,以便db模块可以在获取结果时调用。 它将挂起callback函数,直到数据库有结果,然后在准备就绪时调用函数。 -
由于调用
db.query(...)
立即返回,您的for循环将会完成,调用sample()
将在您提供给查询的callback函数被db模块调用之前触发。
为确保在所有调用完成后运行sample
,您需要跟踪每个查询的完成情况,并在所有查询都返回时触发sample
函数。 在我看来,最简单的方法是在没有向你介绍像“promise”这样复杂的主题的情况下做到这一点,就是使用称为async的模块和它的并行方法。
$ npm安装asynchronous – 保存
var async = require('async'); var queries = []; function inboxUsers(){ uniqueArray.forEach(function (userId) { var getUsername = 'SELECT userName FROM users WHERE userId = ' + userId; queries.push(function (done) { db.query(getUsername, done); }); }); async.parallel(queries, function (err, allQueryResults) { if (err) { return console.error(err); } allQueryResults.forEach(function (queryResults) { queryResults.forEach(function (result) { console.log('single', result.userName); inboxUserList.push(result.userName); }); }); sample(); }); } function sample(){ console.log('same function'); }
这里又是一个捷径,只有更less的捷径和详细的评论。
var async = require('async'); // create an array to store a bunch of functions that the async library // should fire and wait to finish. var queries = []; function inboxUsers(){ uniqueArray.forEach(function (userId) { var getUsername = 'SELECT userName FROM users WHERE userId = ' + userId; var queryFunc = function (done) { db.query(getUsername, function(err, results) { // let the async lib know this query has finished. // the first argument is expected to be an error. // If the err is null or undefined then the async lib // will ignore it. The second argument should be our results. done(err, results); }); // You could make the above even simpler by just passing // the done function as the callback to db.query. I just // didn't want to confuse you by doing that. // db.query(getUsername, done); }; queries.push(queryFunc); }); // Fire all async functions by passing in our queries array. // The async library will wait for them all to call "done()" // before it invokes this final function below. async.parallel(queries, function (err, allQueryResults) { // If any of our queries pass an error to "done" then the async // lib will halt the rest of the queries and immediately invoke // this function, passing in the error. if (err) { return console.error(err); } // queryResults is an array containing the results of each query we made. allQueryResults.forEach(function (queryResults) { queryResults.forEach(function (result) { console.log('single', result.userName); inboxUserList.push(result.userName); }); }); // All your queries are complete and your inboxUserList array // is populated with the data you were after. Now we can call // "sample". sample(); }); } function sample(){ console.log('same function'); }
async
库知道你提供给数组的多less个函数,以便知道在调用最终函数之前应该等待多less次调用。
你很可能遇到这个问题,因为你的db.query()
函数是不同步的。 它期望一个callback函数,它可以在完成时调用。
你的代码inboxUserList.push(...)
将不会被调用,直到你的数据库库查询数据库并得到结果。 同时,您的for循环将继续运行,准备好所有查询,并在所有查询完成之前继续运行。 然后调用sample()
,因为for循环已经完成,即使你传入的callback函数尚未被调用。
有很多解决scheme,但是最简单的代码可能是这样的:
function inboxUsers(){ var completed = 0; for (var i=0; i<uniqueArray.length; i++){ var getUsername = 'SELECT userName FROM users WHERE userId = ' + uniqueArray[i]; db.query(getUsername, function(err, results) { if (err) { console.log('Error in database'); throw err; } for(var i in results){ console.log('single',results[i].userName); inboxUserList.push(results[i].userName); } completed++; if (completed == uniqueArray.length) { sample(); } }); } } function sample(){ console.log('same function'); }