由于Javascript是单线程模型(只在一个线程上运行),因此Javascript同时只能执行一个任务,其他任务必须在后面排队。
Javascript只在一个线程上运行,并不是指JavaScript只有一个线程
同步任务和异步任务
- 同步任务:指没有被引擎挂起,在主线程上排队等待执行的任务。只有前一个任务执行完毕,才能执行下一个任务。
- 异步任务:指被引擎放在一边,不进入主线程、而进入任务队列的任务。只有引擎认为某个异步任务可以执行了,该任务才会进入主线程执行。排在异步任务后面的代码不用等待异步任务结束,会马上执行。
runtime
runtime:即运行环境,它提供一些对外接口供Js调用,以跟外界打交道,比如,浏览器环境、Node环境。不同的运行环境会提供不同的接口,比如,在Node.js中,我们可以通过require引入其他模块,在浏览器环境中则会给我们提供window、DOM操作等接口。因为js的事件处理机制中的异步处理模块是由运行环境提供的,所以不同的运行环境造成事件循环也不同。我们接下来主要了解在浏览器环境中Javascript的事件循环以及任务队列等机制。
任务队列
在JavaScript中,分为两类任务队列:宏任务队列(macro tasks)和微任务队列(micro tasks)。宏任务队列可以有多个,微任务队列只有一个。它们各自包括的任务有什么呢?
- 宏任务:script(全局任务), setTimeout,setInterval,setImmediate,I/O,UI rendering
- 微任务:process.nextTick,Promise,Object.observer,MutationObserver
事件循环(Event Loop)
因为全局任务即script开始也是一个宏任务,所以我理解的浏览器执行任务的步骤为以下三步:
- 取一个宏任务执行(故第一次先执行script,执行完同步代码)。执行完毕后,走下一步。
- 取一个微任务来执行,执行完毕后,再取一个微任务来执行。直到微任务队列为空,执行下一步。
- 更新UI渲染。
Event Loop会无限循环执行上面三步,这就是Event Loop的主要控制逻辑,而由于每个浏览器对UI渲染优化的不同,第三步一般来说不会立即执行,而是会达到阙值之后才执行UI渲染。