0

我试图实现一个事件循环。循环的目的很简单:

  1. 如果队列不为空,则令任务为队列中最旧的条目。
  2. 处理任务
  3. 如果,任务产生一个返回值,缓存它。
  4. 检查队列中的任务。
  5. 如果队列不为空,则采用下一个任务作为当前任务上下文。
  6. 将缓存的返回值传递给新任务。

我以以下方式在 Nodejs 中尝试了一个实现:

function task(){
this.task = Array.prototype.shift.call(arguments);
this.state = 'unprocessed';
this.successCallback = null;
this.failureCallback = null;
}
task.prototype.afterThat = function(){
if(arguments.length > 1){
this.successCallback = Array.prototype.shift.call(arguments);
this.failureCallback = Array.prototype.shift.call(arguments);
}
}
task.prototype._loop = function(){
let ctx = this;
while(ctx.state === 'unprocessed'){ // Source of problem
    setImmediate(this.task, function(){
    // change ctx.state if needed
   }, function(){
   // change ctx.state to 'processed'
   });
 }
}

此实现与事件循环的实现之间的区别如下:

  1. successCallback 可以实例化一个新任务作为其返回,而不是维护一个任务数组,然后将其作为当前任务采用。
  2. 基于处理,任务状态必须改变(或者不改变,如果采用新的挂起任务,其状态为“未处理”)。

我认为问题在于 setImmediate 调用,它无法更改上下文状态,因为当前执行状态永远不会终止,并不断在事件队列中为同一任务添加新调用。

我希望我已经很好地解释了它,并且会感谢一些实施指南,以及我在理解事件队列时可能遇到的任何错误。

谢谢。

4

1 回答 1

2

你的while循环是一个无限循环。JS 是单线程的,因此在你的while循环完成之前没有其他东西可以运行。因为没有其他东西可以运行,ctx.state永远不会改变。因为ctx.state永远不会改变,所以你的while循环永远运行。

每次循环运行时,它都会调用which 调度任务运行,但该任务在循环完成setImmediate()之前无法真正运行。while因此,您陷入了僵局,您将堆积大量要运行的任务列表(最终可能会溢出某些系统资源)。

您需要ctx.state在完成运行任务后进行检查(可能在成功和失败回调中),而不是在这样的循环中。

setImmediate()没有阻塞。您安排的函数在setImmediate()您的循环完成之前不会运行while,但是该循环永远不会找到它的条件,因此它永远不会停止,因为在循环完成while之前没有其他任何东西可以运行。while

相反,调用下一个任务,当它完成时,然后检查ctx.state. 由于您没有展示或描述它的使用方式或您真正想要完成的工作,因此我不确定建议的最佳实施方式。如果您在这方面需要更多帮助,那么您需要向我们展示更多关于您要完成的工作以及您希望如何使用本课程的信息。

我的猜测是,您可以使用 Promise 来完成您正在尝试做的事情,而无需自己编写大量基础设施代码,因为 Promise 是用于排序异步任务的非常好的工具。


仅供参考,您的代码有几处问题,例如缺少右括号和括号。您发布的内容甚至无法正确解析,更不用说运行了。并且,请在发布时正确缩进代码。


于 2017-06-16T16:16:15.433 回答