首页 > 解决方案 > 如何防止 Nestjs 上的事件循环冻结?

问题描述

我正在尝试在 NestJs 中创建异步任务。我希望在向某个控制器发出一个请求后,我的异步任务开始在循环中开始你的长时间工作,然后节点/嵌套进程钢能够回答其他控制器的其他请求。

但是当异步循环开始时,Nest 的所有其他端点都被冻结,直到异步任务完成。

我已经尝试使用setTimeout(), setInterval(), setIntermmediate(),queueMicrotask()Promise.resolve()

我的代码:

// Async task:

private checkTime(baseTime: number, startTimeStamp: number){
   while(true){
      const elapsedTime = Date.now() - startTimeStamp
      console.log(`Elapsed time: ${elapsedTime}`)
      if(elapsedTime > baseTime){
          console.log(`Time excced!`)
          break;  
      }
   }
}

我已经尝试过这样的事情:

queueMicrotask(() => this.checkTime(edge.baseTime, startedTimeStamp))

setTimeout(() => this.checkTime(edge.baseTime, startedTimeStamp), 0)

标签: javascriptnode.jsasynchronousnestjs

解决方案


使用 javascript生成器

代码片段:

function* longTask(time = 1000) {
  const startTime = Date.now();
  // divides the long task into smaller chunks
  yield startTime;

 while (Date.now() - startTime < time) {
    // process(): excute a small chunk of the task
    // and yields the control back to the caller
    yield Date.now() - startTime;
  }

}

function completeLongTask(lt) {
  const val = lt.next();
  if (!val.done) {
    setTimeout(() => {
      completeLongTask(lt);
    }, 0);
  }
}

function triggerTask() {
  const lt = longTask();
  completeLongTask(lt);
}

triggerTask();

尽管上述解决方案有效,但我认为您不需要为您的用例使用生成器。看看这个更简单的解决方案是否适合您。

function checkTime(baseTime, startTimeStamp) {
  const currentTimeStamp = Date.now();
  const elapsedTime = currentTimeStamp - startTimeStamp;
  console.log(`Elapsed time: ${elapsedTime}`);
  if (elapsedTime > baseTime) {
    console.log(`Time excced!`);
    return;
  } else {
    setTimeout(() => {
      checkTime(baseTime, startTimeStamp);
    });
  }
}

推荐阅读