JavaScript学习笔记1——异步编程与事件循环机制(Event Loop)

1. 单线程

js是单线程语言
其异步执行其实是通过事件循环机制模拟出来的,而不是真正的开辟新的物理线程。
为什么js是单线程呢
浏览页面是应用需求,没有很高的实时性需求。js设计为单线程避免了页面交互时因线程执行顺序的不确定给页面渲染带来的不确定(比如一个线程删除这个组件,而另一个线程改变这个组件的样式)。
但是js设计者为提高页面的渲染效率,设计了事件循环机制。将异步事件的处理函数放在任务队列中(比如setTimeout定时到期则将回调函数注册入任务队列,定时的动作是系统完成的,在倒计时期间,浏览器可以继续执行其他js代码),并且当主线程执行栈为空时,从任务队列中取任务执行。这样既避免了引入多线程渲染时需要考虑线程同步的麻烦,又可以获得很好的执行效率。
事件循环机制
同步和异步任务分别进入不同的执行环境,同步的进入主线程,即主执行栈,异步的进入 Event Queue 。主线程内的任务执行完毕为空,会去 Event Queue 读取对应的任务,推入主线程执行。 上述过程的不断重复就是我们说的 Event Loop (事件循环)。

2. 事件的分类和执行顺序

2.1 事件的分类

  • 微任务

process.nextTick
Promise.then&&async/await
MutaionObserver

【注】process.nextTick是先于其他微任务执行的,即总是在一堆微任务中先执行它。其他微任务则按照入队列的先后顺序执行。

  • 宏任务

script( 整体代码)
setTimeout
ajax
文件读取
setInterval
setImmidiate

【注1】微任务和宏任务都是异步事件,其分别在不同任务队列中,执行完一个宏任务,总是要把微任务队列全部执行完,清空。
【注2】setTimeout是当定时到期后,将定时事件加入到宏任务队列中
【注3】setImmidiate虽然也是宏任务,但是其执行顺序靠后,即当setTimeout和setInterval任务都执行完毕才会去执行它,前两个任务按照队列顺序执行

2.2 宏观执行顺序:

一个宏任务(javascript代码) —> 清空所有微任务 —> 一个宏任务 —> …(不断循环)

2.3 总体执行顺序:

  1. 执行javascript代码,这是个宏任务:同步的就执行。【注】Promise的参数函数和await之前的代码内容是同步执行的。遇到任务源,若为宏任务则添加到宏任务相应的任务队列中(宏任务可以有不同的任务源,因此添加的队列也是不同的)。若为微任务则添加到微任务队列中(微任务只有一个队列)。来自同一任务源的任务会被添加到同一队列中。
  2. javascript原始代码执行完毕之后,按照宏观执行顺序,开始执行微任务,将微任务队列清空。
  3. 微任务队列清空之后,再提取一个宏任务执行。
  4. 从2开始循环

小结

知道了事件的执行顺序,就可以知道我们的js代码的执行顺序,从而对js异步编程有更好的把控。

【补充1】
setTimeout/Promise 等API是任务源,而进入任务队列的是由他们指定的具体执行任务。来自不同任务源的任务会进入到不同的任务队列。其中 setTimeout 与 setInterval 是同源的。
【补充2】
整体script作为第一个宏任务首先进入主线程执行
【补充3】
执行栈,任务队列
宏任务队列可以有多个
微任务队列只能有一个

你可能感兴趣的:(JavaScript,javascript)