假设我们有一个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);
答案 0 :(得分:2)
您应该考虑使用async/await。您必须重新编写所有适用的代码才能使用Promises或使用为您执行此操作的库。
您的主要功能可能看起来像这样;
(async function main(){
try{
await taskFunction();
await backupGetFunction();
await backupSetFunction();
res.send('I am done');
} catch (error){
throw error;
};
})();
一切都将按顺序执行,最后,它将按预期重新发送'我完成'。
此解决方案背后的复杂性是,任何依赖main函数的函数都需要使用promises才能使流保持异步。
例如,您的备份功能最初可能是;
function backupExample(){
fs.copyFile('source.txt', 'destination.txt', (err) => {
if (err) throw err;
console.log('source.txt was copied to destination.txt');
});
};
必须转换为以下内容才能使用async / await;
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');
});
});
};
promises充当主async / await函数的指导,因此它知道异步函数何时完成。
答案 1 :(得分:0)
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');
请注意,如果您使用async / await功能,则至少需要拥有v7及更高版本的节点。或 - 运行节点时的--harmony-async-await标志