首页 > 解决方案 > 调用堆栈和事件循环 - 为什么要等待空堆栈?

问题描述

我知道当调用堆栈为空时,消息会从队列中进入调用堆栈。但是,如果事件循环可以将消息从队列直接推送到调用堆栈而不等待,那不是更好吗?这种行为背后的原因是什么?如果事件循环会在准确的时间推送消息,我们总是可以依赖 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");

由于一致性原因,它可能永远不会改变,但我仍然很好奇。也许我什么都没看到,等待空堆栈的概念背后有严重的技术原因。您是否可以访问一些有关 JS 中的架构决策的文章,或者您是否知道需要这种行为的基本示例?有很多关于 JS 如何工作的文章,但我找不到像“为什么事件循环完全那样工作”这样的文章。任何帮助将不胜感激。

标签: javascriptv8event-loop

解决方案


V8 开发人员在这里。这个问题似乎是基于对“调用堆栈”是什么的误解:它不是任何人都可以将东西推送到上面的数据结构。相反,它是一组函数相互调用时事物的当前状态的术语。将另一个函数“推入”调用堆栈的唯一方法是在当前执行的函数调用它时。如果事件系统在你的函数中随机插入随机调用,那将导致一个非常奇怪的编程模型。

您可以设计一个概念上相似的编程环境,但不是将任何内容推送到调用堆栈上,而是中断和暂停当前正在执行的任何内容,然后执行setTimeout-scheduled 函数(或事件处理程序等),然后恢复之前的执行。您必须解决的一个问题是:如果这种情况重复发生,即,如果预定功能被另一个预定功能中断,而另一个预定功能又被另一个预定功能打断怎么办,等等?如果一个计划函数需要永远完成怎么办:之前执行的代码什么时候才能再次取得进展?此外,虽然这可以在单线程世界中完成,但获得随机中断是并发(从一致性的角度来看相当于并行/多线程),所以你需要像锁这样的同步原语(基本上,有一种让函数说“不要打断这一部分”的方式——这反过来意味着你实际上不能保证调度请求的准确性)。大学教师'

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


推荐阅读