1

我有一个 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

4 回答 4

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 中的 async/await 的信息:

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

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

于 2018-12-21T15:17:35.127 回答
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);
  }
 });
})()
于 2018-12-21T14:50:56.747 回答
0

我强烈建议你看看异步库,它是处理这类事情的一个很好的库。

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

例如

// 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
     }
});
于 2018-12-21T16:06:11.770 回答
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();
  });
}
于 2018-12-22T08:44:02.400 回答