如何阻止事件循环直到完成运行异步任务
问题描述:
假设我们有一个Web服务器接收http请求并发回响应。它有很多端点,包括这一个如何阻止事件循环直到完成运行异步任务
/task
应该有一些异步任务,如从Redis
读/写,我想阻止事件循环,直到这些任务完成。我知道这是不合理的,因为事件循环还需要继续努力以接收Redis
的事件。所以我想把这个逻辑放在一个单独的脚本中,并使用child_process.spawnSync
来执行并等待它并阻止当前的事件循环。这个解决方案可以工作,但我的问题是我的逻辑,异步任务比本示例中提到的更复杂,它们依赖于当前脚本,它们是框架的一部分,将它们分离为单独的脚本并不容易。有什么建议么 ?
var express = require('express');
var app = express();
var redis = require('./redis');
// Block the event loop until finish doing some async tasks
app.get('/task', function(req, res) {
// Block the event loop now
redis.get('backup', function(error, backup) {
// ...... Do some changes to the backup data
redis.set('backup', backup, function(error, result) {
// Unblock the event loop now
res.send('I am done');
});
});
});
// To check if the event loop is really blocked
counter = 0;
setInterval(() => { console.log(counter++) }, 100);
app.listen(5000);
答
你应该看看使用async/await。您必须重新编写所有适用的代码才能使用Promises,或使用为您提供的库。
您的主要功能可能看起来像这样;
(async function main(){
try{
await taskFunction();
await backupGetFunction();
await backupSetFunction();
res.send('I am done');
} catch (error){
throw error;
};
})();
一切都将按顺序执行,最后,它会res.send'我完成'按预期。
该解决方案背后的复杂性是任何依赖主函数的函数都需要使用promise来保持流异步。
作为一个例子,您的备份功能最初可能是;
function backupExample(){
fs.copyFile('source.txt', 'destination.txt', (err) => {
if (err) throw err;
console.log('source.txt was copied to destination.txt');
});
};
当它必须转换为以下内容才能使用async/await;
async function backupExample(){
return new Promise((resolve, reject) => {
fs.copyFile('source.txt', 'destination.txt', (err) => {
if (err) reject(err);
resolve('source.txt was copied to destination.txt');
});
});
};
该承诺充当主要异步/等待函数的指导,以便它知道异步函数何时完成。
答
你可以使用。
redis.getAsync('backup')
.then(res => {
// ...... Do some changes to the backup data
return redis.set('backup', backup)
})
.then(()=>res.send('I\'m done'))
或
let backup = await redis.getAsync('backup');
// ...... Do some changes to the backup data
redis.set('backup', backup);
res.send('I\'m done');
注意:如果使用异步/等待你需要有至少节点V7和最多的功能。或者在运行节点时使用--harmony-async-await标志
'有什么建议?',是的。不要阻止。目前还不清楚为什么在你的描述中你也需要.. – Keith
为什么我需要阻止并不重要,问题在于如何。无论如何,我需要将一些会话状态备份到Redis中,并防止接收可能导致这些数据无效的事件,直到完成将当前会话状态存储到Redis中,然后继续处理接收到的事件,这就是为什么我需要阻止事件循环以让这些事件排队并防止竞赛状况。 – faressoft
您可以在不阻塞主线程的情况下做到这一切。无论如何,你说任何建议,那是我的。如果这是一个多用户网站,这样做会削弱它。 – Keith