节点js等待函数返回以继续进行循环

时间:2018-12-21 14:41:57

标签: node.js for-loop

我有一个for循环,它在每个步骤中都调用一个函数。

该函数调用API,但我不知道获得响应需要多长时间。

我需要等到函数updatePE()返回一个值,然后循环进行下一步。

 db.query("SELECT * FROM tb_table where active = true;", (err, result) => {
  if (err) {console.log('ERROR'); return; }

for (const key in Object.keys(result.rows)) {

    updatePE(result.rows[key].b,result.rows[key].s,result.rows[key].k);

}
});

4 个答案:

答案 0 :(得分:2)

假设您的update函数是异步的(基于Promise)并且可以使用async/await(至少需要Node 8.x),则可以通过以下方式编写代码:更新将并行进行(从代码角度出发,因为实际上NodeJS在单线程的执行队列顶部运行):

 // Note "async" keyword added to the function.
 // It means it'll be converted to Promise and its internal implementation
 // can use "await"
 db.query('SELECT * FROM tb_table where active = true;', async (err, result) => {
  if (err) {
    // A good idea - you should throw a proper error here
    console.log('ERROR'); return; 
  }

  // We'll collect all the promises in that array
  const updatePromises = [];
  for (const key in Object.keys(result.rows)) {
    // IMPORTANT NOTE! Updates will start executing here, but we'll
    // Wait for finishing them later
    updatePromises.push(
      updatePE(result.rows[key].b,result.rows[key].s,result.rows[key].k)
    );
  }

  // Here we wait until all the updates are finished
  await Promise.all(updatePromises);

  // Here you can put all your code that should happen *AFTER* updates are finished
});

有关JS中异步/等待的更多信息:

值得一提的另一件事-您的查询代码使用了回调,在现代JS世界中,回调被认为是过时的-请检查您的db库是否公开了Promise接口-它将大大简化代码并提供一致的代码轻松处理错误的方法。

如果要在现有代码中正确使用Promises,并且不使用Promise兼容的库,则可以使用:

答案 1 :(得分:0)

如果updatePE()是同步函数,那么它将等待该函数调用的返回,如果它是async函数,则尝试将await放在该函数的前面直到函数返回

await updatePE() //make sure updatePE() is an async function

喜欢

async function updatePE(param1, param2, param3){
  return new Promise((resolve, reject)=>{
    //do something and call 
    //resolve(true)
  })
}

请确保您只能在await函数内调用async,所以调用者函数也必须是async

(async function(){
 db.query("SELECT * FROM tb_table where active = true;", (err, result) => {
  if (err) {console.log('ERROR'); return; }
  for (const key in Object.keys(result.rows)) {
    await updatePE(result.rows[key].b,result.rows[key].s,result.rows[key].k);
  }
 });
})()

答案 2 :(得分:0)

我强烈建议您看一下async库,它是处理此类问题的好库。

现在让我们谈谈您的问题以及如何解决。假设updatePE是您自己的函数,则可以将该函数转换为promise或向其中添加回调,这样您就可以知道它何时完成执行。

例如

// Promise implementation
function updatePE(x, y, z) {
   return new Promise(function(resolve, reject){
       // Do your work here and when is done resolve it
       resolve();
   });
}

// Callback implementation
function update(x, y, z, callback)
{
     // Do your work here and when is done, callback
     callback()
}

现在使用异步库,您可以执行以下操作

// If your updatePE uses callback
async.forEach(result.rows, function(row, callback) {
     updatePE(x, y, z, function() {
        callback(null)
     });
}, function(err){
     if (err) {
        // Loop is finished with an error
     } else {
        // Loop is finished without an error
     }
});

// If your updatePE uses promise
async.forEach(result.rows, function(row, callback) {
     updatePE(x, y, z)
        .then(function(){
           callback(null)
        })
        .catch(function(err){
           callback(err)
        })
}, function(err){
     if (err) {
        // Loop is finished with an error
     } else {
        // Loop is finished without an error
     }
});

答案 3 :(得分:0)

使用异步库执行此操作。它仅在触发回调后才允许您进入for循环的下一个迭代。像这样:

var async = require('async');
async.forEach(Object.keys(result.rows), async function(key, cb) { 
  await updatePE(result.rows[key].b,result.rows[key].s,result.rows[key].k);
  cb();
}, function(err) {
   // Here you know that the loop has completed (with err or success).
});

请务必在您的updatePE中返回承诺。像这样:

function updatePE(b, s, k) {
  return new Promise(function(resolve, reject) {
    // Your update code here.
    if(updateSuccessful) resolve();
    else reject();
  });
}