循环的Javascript事件

109 阅读5分钟

Javascript的事件循环

照片:Tine IvaničonUnsplash

一般来说,编程或软件开发是一个有趣的领域,其知识每天都在以指数级的速度增长。编程语言和它们的配套框架总是在不断发展,变得越来越神奇,以至于有时会显得很麻烦。好在基本原理很少改变。框架和其他工具给我们带来的简化和速度是非常受欢迎的,但偶尔你会遇到一个问题,需要你知道引擎盖下发生了什么。

我写这篇博客不是为了指出对了解Javascript事件循环的工作原理的具体需要,咳!!咳!!异步Javascript。我只是说,我觉得偶尔深入研究一下是很有意义的,因为javascript是单线程的,你永远不知道这些知识何时会派上用场。

外面有一些更有经验的Javascript老手写的关于这个主题的博客。我以前读过其中的一些,但我不能完全理解是怎么回事,直到我在Pluralsight上学习了Sumer Buna的高级Node.js课程,这是其中的一个子课题。我没有试图为任何人或任何平台做广告,但也许可能是我在视觉上学习得更好。也就是说,我希望我从那门课程中获得的知识和我在互联网上读到的内容能够帮助填补你在网络上搜寻这种解释时可能出现的空白。

Javascript是一种单线程编程语言,函数的执行是一次完成的,与C或Java不同。在C和Java中,当另一个线程中的函数(funcB)触发中断时,一个函数(我们称它为funcA)可以被停止。在这种情况下,funA的状态被保存,控制权被移交给funcB。一旦粗鲁的funcB执行完毕,控制权就会返回给funcA,它自己的执行就会继续。

为了在Javascript的单线程中管理许多函数,事件循环与调用栈和消息队列一起派上了用场。所有的函数都作为消息被添加到消息队列中。对于有监听器的浏览器中的点击等事件也是如此。顾名思义,消息队列是一个先入先出的数据结构,它将确保最古老的事件首先得到处理,最新的事件最后得到处理。

为了了解事件循环、调用栈、消息队列甚至是对象堆的概念模型,你可能会遇到一个类似于下面的图表

代表性的概念。图片来源:MDNdeveloper.mozilla.org/en-US/docs/…

事件循环的工作是从消息队列中获取消息并调用其相应的函数,即回调。一个函数以堆栈帧的形式被放在调用堆栈上执行。在点击事件的情况下,监听器函数及其内容被放在调用栈上。一个堆栈框架包含一个函数的所有参数和变量。如果这个函数调用另一个函数,这个函数的框架将被放在堆栈中其调用者的上面,以此类推。一旦最上面的函数的堆栈框架执行完毕,它就会从调用堆栈中弹出,并继续执行到当前最上面的堆栈框架。在此过程中,事件循环一直在检查堆栈是否为空。当调用栈为空时,事件循环检查队列中是否有其他消息在等待,并像以前一样开始处理队列中最古老的消息。

medium.com/media/335d8…

我将使用上述函数列表来演示这些概念,大致详述Arnold Shwarzenneger在各个行业中的职业道路。让我们假设在window.onload事件中,浏览器调用becomeAbodyBuilder(24,197)。该事件将作为一条消息被放在消息队列中。稍后,在javascript运行时,事件循环将不得不处理这个消息,从队列中删除该消息并调用其相应的函数。一个带有参数和dateOfbirth变量的调用堆栈框架将被创建,becomeAbodyBuilder的堆栈框架将是堆栈中的第一项,因此是最后被处理的。

从这段代码中可以看到堆栈的可视化,在下一张图中。这一连串的图是依次从1到6的调用堆栈的快照,如黄框所引用的。栈1显示了由于调用becomeAbodyBuilder()而产生的框架。Console.log()是堆栈最高帧中的函数。它被执行并立即被弹出。接下来becomeGovernor()也被弹出,becomeAnActor()通过调用console.log()继续执行,如调用栈快照3所见,console.log()也被立即弹出。这种行为一直持续到快照6,在那里 becomeABodyBuilder() 也被弹出,我们有一个空的调用栈。

有时,EventLoop会发现调用栈是空的,并会检查我们是否有一个消息在消息队列中等待。如果它发现了一个,那么一个类似于我们刚刚看到的故事将再次展开。

这种对消息的单一处理确保了消息被处理完毕,从而消除了与多线程相关的一些问题。一个很好的例子是,上面的funcB可能会改变被funcA操作的变量,导致可靠性或准确性问题。

这一部分我就说到这里吧,因为我不想用异步的javascript让这个博客变得更复杂,而异步javascript通常是由setTimout()函数和它的兄弟姐妹们带来的。我的主要目的只是为了让大家了解事件循环、调用栈和消息队列是如何协同工作的,以确保javascript代码在单线程环境下无缝执行。


Javascript事件循环最初发表在The Andela Way上,在Medium上,人们正在通过强调和回应这个故事来继续对话。