JS的单线程和事件循环机制

Posted by Vison on January 6, 2019

从单线程开始谈起

众所周知,JavaScript是一门单线程的非阻塞的脚本语言,这是由于它诞生时的用途所决定的:与浏览器交互。 单线程意味着,javascript代码在执行的任何时候,都只有一个主线程来处理所有的任务。 非阻塞则是当代码需要进行一项异步任务(无法立刻返回结果,需要花一定时间才能返回的任务,如I/O事件)的时候, 主线程会挂起(pending)这个任务,然后在异步任务返回结果的时候再根据一定规则去执行相应的回调。

单线程是必要的,也是javascript这门语言的基石,原因之一在其最初也是最主要的执行环境——浏览器中,我们需要 进行各种各样的dom操作。试想一下 如果javascript是多线程的,那么当两个线程同时对dom进行一项操作, 例如一个向其添加事件,而另一个删除了这个dom,此时该如何处理呢?因此,为了保证不会 发生类似于这个例子中的情景, javascript选择只用一个主线程来执行代码,这样就保证了程序执行的一致性。

当然,现如今人们也意识到,单线程在保证了执行顺序的同时也限制了javascript的效率,因此开发出了web worker技术。 这项技术号称让javascript成为一门多线程语言。

然而,使用web worker技术开的多线程有着诸多限制,例如:所有新线程都受主线程的完全控制,不能独立执行。 这意味着这些“线程” 实际上应属于主线程的子线程。另外,这些子线程并没有执行I/O操作的权限, 只能为主线程分担一些诸如计算等任务。所以严格来讲这些线程并没有完整的功能,也因此这项技术并非改变了javascript语言的单线程本质。

可以预见,未来的javascript也会一直是一门单线程的语言。

事件循环

前面提到javascript的另一个特点是“非阻塞”,那么javascript引擎到底是如何实现的这一点呢?答案就是——event loop(事件循环)。

事件循环(event loop)是JavaScript中非常重要的概念,清晰的理解事件循环的执行顺序可以让我们减少代码执行的不确定性, 是我们写出高质量代码的保证

虽然node.js中的也存在与传统浏览器环境下的相似的事件循环。然而两者间却有着诸多不同,故把两者分开,单独解释。

js的事件循环机制

图中的stack表示我们所说的执行栈,web apis则是代表一些异步事件,而callback queue即事件队列。

练习

答案: 3,4,6,8,7,5,2,1