узел js ожидает возврата функции для продолжения цикла for - PullRequest
0 голосов
/ 21 декабря 2018

У меня есть цикл 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 голосов
/ 22 декабря 2018

Сделайте это с помощью асинхронной библиотеки.Он позволяет перейти к следующей итерации цикла 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();
  });
}
0 голосов
/ 21 декабря 2018

Предполагая, что ваша функция 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-совместимыйБиблиотека, вы можете использовать:

0 голосов
/ 21 декабря 2018

Я настоятельно рекомендую вам взглянуть на библиотеку async , это отличная библиотека для такого рода вещей.

Теперь давайте поговорим о вашей проблеме и о том, как ее можно решить,предполагая, что 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
     }
});
0 голосов
/ 21 декабря 2018

Если 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);
  }
 });
})()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...