如何阻止事件循环,直到完成异步任务

时间:2017-10-28 21:08:01

标签: javascript node.js asynchronous redis event-loop

假设我们有一个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);

2 个答案:

答案 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标志