代码之家  ›  专栏  ›  技术社区  ›  Bartłomiej Gładys

调用堆栈和事件循环-为什么要等待空堆栈?

  •  1
  • Bartłomiej Gładys  · 技术社区  · 6 年前

    我知道当调用堆栈为空时,消息从队列进入调用堆栈。如果事件循环可以将消息直接从队列推送到调用堆栈而不等待,这不是更好吗?这种行为背后的原因是什么?如果事件循环在某个确切的时间推送消息,我们可以始终依赖函数,如setTimeout等。

    setTimeout(() => console.log("I want to be logged for 10ms, but I will never be :("), 10);
    
    // some blocking operations
    for(let i = 0; i < 500000000; i++){
      Math.random() * 2 + 2 - 3;  
    }
    
    console.log("I'll be logged first lol");

    1 回复  |  直到 6 年前
        1
  •  9
  •   jmrk    6 年前

    我是V8开发者。这个问题似乎是基于对“调用堆栈”是什么的误解:它是

    setTimeout -改为调度函数(或事件处理程序等),然后恢复先前的执行。你必须解决的一个问题是:如果这种情况重复发生怎么办,也就是说,如果一个预定函数被另一个预定函数打断,而这个预定函数又被另一个预定函数打断怎么办,以此类推?如果一个预定的函数要花很长时间才能完成,那该怎么办:以前执行的代码什么时候才能再次取得进展?另外,虽然这可以在单线程世界中完成,但获得随机中断就是并发性(从一致性的角度来看,这相当于并行/多线程),因此您需要同步原语,如锁(本质上,有一种方法让函数说“不要中断这个部分”--这反过来意味着您实际上不能保证调度请求的准确性)。不要低估所有这些都会给程序员带来的复杂性成本:在编写代码时,他们必须记住任何东西都可能随时中断,另一方面,一个函数可能要处理的任何数据可能还没有准备好,因为生成它的另一个函数还没有运行完。

    简而言之,JavaScript的事件循环系统就是这样,因为该语言避免了并发,而随机中断函数来执行其他函数就是并发,即使在单线程系统上也是如此。