Toc
0 results found
FBB
JS执行机制
2019/03/07 前端 JS

关于JS执行机制这一块内容,一直是自己比较难以理解的知识点,结合自己看的资料与代码实践,写一篇总结。

首先,我们熟知JS是单线程语言,再同一时间只能做一件事情。所以JS是按着语句顺序依次执行下来的。

let a = 1
console.log(a)

let b = 2
console.log(b)

//依次输出1 2

之后,接触了很多知识之后,我们认识到了两个定时器setTimeout和它的兄弟setInterval。这一段代码中,按着之前的逻辑应该依次输出1 2 3。

但是实际情况的输出为1 3 2。

console.log(1)

setTimeout(() => {
  console.log(2)
}, 1000)

console.log(3)   //1 3 2

在这个时候我们就要引入两个概念: 同步任务和异步任务。

  • 同步任务: 在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务
  • 异步任务: 不进入主线程,而进入”任务队列”(task queue)的任务,只有”任务队列”通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行

而上述的setTimeout和setInterval就是异步任务。那整个执行机制就可以用下面的图片表示。

image.png

图片用文字表达就是:

  • 当任务进入执行栈,首先会判断是同步任务还是异步任务
  • 当为同步任务的时候进入主线程直接执行;当为异步任务的时候,进入Event table注册函数,函数注册完成之后推入Event queue,等待主线程空闲时执行。
  • 一旦主线程空闲,就会从任务队列中取对应的函数,进入主线程
  • 然后重复上述过程,称之为事件循环

实例练习:

console.log(1)

setTimeout(() => {
  console.log(2)
}, 5000)

console.log(3)

setTimeout(() => {
  console.log(4)
}, 1000)   //1 3 4 2

按着上述理论,这段代码的执行过程应该如下:

  • 整段代码进入主程序
  • console是同步任务,直接输出
  • setTimeout是异步任务,进入event table中注册函数
  • console是同步任务,直接输出
  • setTimeout是异步任务,进入event table中注册函数。此时,在event table中有两个setTimeout在注册函数,然而第二个setTimeout只需要等待1000ms完成注册,第一个则需要等待5000ms完成注册,所以第二个setTimeout比第一个先推入Event queue。所以当第二个console执行完毕的时候,是第二个setTimeout先进入主线程执行。
  • 综上所述,最后的输出结果为1 3 4 2

setTimeout这个函数,是经过指定时间后,把要执行的任务加入到Event Queue中,又因为是单线程任务要一个一个执行,如果前面的任务需要的时间太久,那么只能等着,导致真正的延迟时间远远大于设置时间。对于执行顺序来说,setInterval会每隔指定的时间将注册的函数置入Event Queue,如果前面的任务耗时太久,那么同样需要等待。

接着,我们认识了Promise这个异步函数。打开了新世界大门。

我们又对任务有了更精细的区别宏任务和微任务。

  • 宏任务: 整段代码、setTimeout、setInterval
  • 微任务: promise、process.nextTick(callback)

按着宏任务微任务来说,执行机制就应该如下图。

image.png

实例练习:

setTimeout(function() {
  console.log(1);
}, 4000)

new Promise(function(resolve) {
  console.log(2)
  resolve()
}).then(function() {
  console.log(3)
})

console.log(4)   //2 4 3 5 1

setTimeout(function() {
  console.log(5);
}, 1000)

按着上述理论,这段代码的执行过程应该如下:

  • 整段代码作为宏任务开始执行
  • 遇到宏任务setTimeout,加入宏任务Event queue(注册过程同上)
  • 遇到new Promise立即执行,then函数推入微任务Event queue
  • 遇到console立即执行
  • 遇到宏任务setTimeout,加入宏任务Event queue(注册过程同上),由于它完成注册的时间早于第一个setTimeout,会成为第二个执行的宏任务
  • 第一个宏任务执行完毕,检查微任务Event queue中包含任务,执行
  • 第一轮事件循坏结束,开始第二轮事件循环,直至结束。

事件循环(Event Loop)就是JavaScript的执行机制。

这篇文章思路来源于这一次,彻底弄懂 JavaScript 执行机制,也是自己对学习完这个知识点的一个总结。

打赏
支付宝
微信
本文作者:FBB
版权声明:本文首发于FBB的博客,转载请注明出处!