NodeJS:回调和异步调用

时间:2017-08-23 19:51:08

标签: node.js mongodb express mongoose callback

我一直盯着我的屏幕看了太长时间,似乎无法弄清楚这一点...... 基本上我使用mongoose做3个查询,每个查询都建立在另一个查询的结果上。由于某种原因,在孩子完成任务之前父母呼叫已经完成。这是我的代码,为什么父母不等待继续直到孩子完成工作?我怎样才能使代码运行,因为我希望它:-)

我被告知要使用promises,但它看起来很复杂,我认为使用回调就足以处理异步调用或者我错了吗?

var ctr = 0; // counter 1
var ct2 = 0; // counter 2

//Array to be used for the header of the csv file
var mainArr = [["Personeelsnummer", "Chauffeur", "Week 1", "Week 2", "Week 3", "Week 4"]];

    // Find all users in the database
    User.find({}).exec(function (err, users){
        // forEach user, push some basic data into tempArr
        // and lookup planned weeks (geplandeWeken) using another mongoose function
        users.forEach(function(user){
            var tempArr = [];
            tempArr.push(user.personeelsnummer);
            tempArr.push(user.fullName);

            user.geplandeWeken.forEach(function(week1){
                Week.findById(week1, function(err, foundWeek){
                    tempArr.push(foundWeek.week);

                    ctr++;
                    if(ctr === user.geplandeWeken.length){
                        mainArr.push(tempArr);
                        console.log(mainArr);
                    }
                });
            });
            ct2++;
        }); 

        if(ct2 === users.length){
            console.log(ct2);
            csv.write(mainArr, {headers:true}).pipe(res);           
        }       
    });

如此长的故事简短: users.forEach user.geplandeWeken.forEach 能够完成任务之前完成。在收集任何数据并将其存储到csv文件之前,会将csv文件发送给用户。

2 个答案:

答案 0 :(得分:1)

首先,您已经同步编写了代码,这就是为什么它不等待您的依赖关系解析并继续之后。

为此,您将要使用回调或承诺。我更喜欢后者作为一些复杂的代码,当写回调可能会导致回调地狱。

有关承诺的参考:Promises

根据您的要求,您可以使用以下承诺: 通过npm安装蓝鸟(我更喜欢它,你也可以使用任何其他包),并在你的主文件中使用它

var Promise = require("bluebird");
mongoose.Promise = Promise;

要使用promises制作自定义函数,您可以使用以下

function sample(required Params){
  return new Promise(function(resolve,reject){
   //do things you want to perform
   resolve(params you want to sendBack)//if everything has worked correctly
   reject(params you want to sendBack)// if something goes wrong
  };
}

根据你的代码,我已经用我能理解的最好的承诺修改了它

var ctr = 0; 
var ct2 = 0;

var mainArr = [["Personeelsnummer", "Chauffeur", "Week 1", "Week 2", "Week 3", "Week 4"]];
User.find({})
.then(function(users){
  for(user in users){
   var tempArr = [];
   tempArr.push(user.personeelsnummer);
   tempArr.push(user.fullName);
   for(week1 in user.geplandeWeken){
    Week.findById(week1)
    .then(function(foundWeek){
      tempArr.push(foundWeek.week);
      ctr++
      if(ctr === user.geplandeWeken.length){
          mainArr.push(tempArr);
          console.log(mainArr);
      }
    });
   }
   if(ct2 === users.length){
      console.log(ct2);
      csv.write(mainArr, {headers:true}).pipe(res);
   }
 }
})
.catch(function(err){
 //this is the common error handler
 //code for handling error
});

个人因为你正在使用基于json的langauage,即javasacript尝试使用你的tempArr作为json,因为如果你需要为tempArr变量添加一些新值或者你决定使用它会给你更多灵活性并且将来变化不大随机存储变量

中存储的值的顺序
var tempArr = {};
tempArr[keyName]=keyValue;

并像这样访问它     tempArr.keyName;

要将for循环转换为异步循环,请使用以下方法

function asyncFor(i){
   if(i < users.length){
     let user = users[i];
     //perform your rest of the actions and execute the last statment
     asyncFor(i++);
   }else{
     return;
   }
}asyncFor(0);

希望这能回答您的问题

答案 1 :(得分:0)

Week.findById是异步的。它不会阻止代码执行,并继续执行下一条指令。

如果您需要等待许多异步任务完成才能继续,那么您可以使用Promises

var userPromises = users.map(user => {
    return new Promise((resolve, reject) => {
        // do something async
        // resolve(value) when complete 
    })
})

Promise.all(userPromises).then(results => {
    // do something with results
})