我有一个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);
}
});
答案 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兼容的库,则可以使用:
bluebird
库及其令人惊叹的Promise.fromCallback
或Promise.promisifyAll
。此处更多内容:http://bluebirdjs.com/docs/api-reference.html 答案 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();
});
}