Javascript 当for循环在节点js中完成时调用函数

Javascript 当for循环在节点js中完成时调用函数,javascript,node.js,function,for-loop,Javascript,Node.js,Function,For Loop,在这段代码中,我在for循环之后调用了函数sample(),但在for循环结束之前调用了sample()函数 我想在for循环结束时调用sample()函数。我是stackoverflow的初学者,如果我有错误,请向我道歉。谢谢您很可能遇到此问题,因为您的db.query()函数不同步。它需要一个回调函数,完成后可以调用该函数 在数据库库查询数据库并获得结果之前,不会调用您的代码inboxUserList.push(…)。同时,for循环将继续运行,准备好所有查询并在它们全部完成之前继续。然后调

在这段代码中,我在for循环之后调用了函数sample(),但在for循环结束之前调用了sample()函数


我想在for循环结束时调用sample()函数。我是stackoverflow的初学者,如果我有错误,请向我道歉。谢谢

您很可能遇到此问题,因为您的
db.query()
函数不同步。它需要一个回调函数,完成后可以调用该函数

在数据库库查询数据库并获得结果之前,不会调用您的代码
inboxUserList.push(…)
。同时,for循环将继续运行,准备好所有查询并在它们全部完成之前继续。然后调用
sample()
,因为for循环已经完成,即使传入的回调尚未调用

有许多解决方案,但也许当前代码最简单的解决方案如下:

same function
single user1
single user2
single user3
函数inboxUsers(){
var完成=0;

对于(var i=0;i您对
db.query
的调用是异步的。这意味着:

  • db.query(…)
    的调用立即返回,不返回任何内容

  • 您没有将返回值赋给变量(
    var results=db.query(…)
    ),而是将作为参数传入,以便db模块在获取结果后可以调用。它将挂起回调函数,直到数据库获得结果,然后在准备好时调用该函数

  • 由于对
    db.query(…)
    的调用将立即返回,因此for循环将完成,对
    sample()
    的调用将在db模块调用您提供给查询的回调函数之前启动


  • 要确保
    sample
    在所有调用完成时运行,您需要跟踪每个查询的完成情况,然后在所有查询返回时启动
    sample
    函数。我认为,最简单的方法是在不向您介绍“承诺”等复杂主题的情况下执行此操作,具有名为的模块及其方法

    $npm安装异步--保存


    这里是再次,但采取较少的捷径和详细的评论

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

    async
    lib知道您向数组提供了多少函数,因此它知道在调用最终函数之前应该等待多少次对
    done
    的调用。

    欢迎使用StackOverfow!请更新您的问题,将输出包括到控制台,或者描述您如何知道调用了该函数示例循环结束之前。
    for
    循环将始终在
    示例运行之前完成;
    db.query
    ,但是,它似乎是异步的,这意味着
    示例将在您传递给它的回调之前运行。@dVid我更新了我的问题。这些包括控制台输出请参见下面的答案。这是一个非常常见的问题可以轻松修复的异步场景:)我遇到了这个错误,
    TypeError:undefined不是inboxUsers(C:\Users\yathu\IdeaProjects\chatting\app.js:148:16)
    ,这是一行148:})。然后(function(){@user3702886您在数据库中使用什么库?var mysql=require('mysql'));在这种情况下,您甚至不需要使用
    .then
    .on
    。只需将
    completed++
    和下面的
    if
    语句向上移动到for循环下面的查询回调函数中。这样,您就可以完全避免承诺和事件处理程序,这对于初学者来说有些复杂。@AlexFord这是一个很好的观点!我简化了我的示例以反映这一点。在数组中使用相同的用户名,在sample()中打印inboxUserList,我得到了这个结果
    ['kabilan','kabilan','kabilan']
    我还更改了(var I=0;I
    console.log('single',result.username'))
    此行打印未定义我无法识别示例中的错误,并且我无法测试它,因为我没有您正在运行的完整代码。我将首先检查传递给
    async.parallel
    回调(
    allQueryResults
    )的内容然后看看它是什么样子。它应该是一个数组数组。每个嵌套数组都是相关查询的结果。尝试
    console.log(result);
    也可以查看
    result
    是什么。如果它不是您期望的,那么我们可以从那里找到原因。
    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');
    }
    
    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');
    }
    
    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');
    }