任务队列
首先我们需要明白几个事情:
- JS 分为同步和异步任务
- 同步任务都在主线程上执行,形成一个执行栈
- 主线程之后,事件触发器管理着一个任务队列,只要异步任务有了运行结果,就在任务队列之中放置一个事件
- 只是执行栈中的同步任务执行完,浏览器就会读取任务队列,将可以执行的异步任务添加执行栈之中执行。
事件循环是通过任务队列的机制来进行协调的,一个 Event Loop 中,可能有一个或多个任务队列,一个任务队列便是一系统有序任务的集合。每个任务都有一个任务源,源自同一个任务源的task ,必须放在同一个任务队列,不同源的任务则被放到不同的队列中。进入任务队列是他们指定的具体的执行的任务。
宏任务
(macro)task(又称之为宏任务),可以理解为执行栈每次执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行)
览器为了能够使得JS内部(macro)task与DOM任务能够有序的执行,会在一个(macro)task执行结束后,在下一个(macro)task 执行开始前,对页面进行重新渲染。
(macro)task主要包含:script(整体代码)、setTimeout、setInterval、I/O、UI交互事件、postMessage、MessageChannel、setImmediate(Node.js 环境)
微任务
microtask(又称为微任务),可以理解是在当前 task 执行结束后立即执行的任务。也就是说,在当前task任务后,下一个task之前,在渲染之前。
所以它的响应速度比 settimeout 会更快,因为无需等渲染。也就是说,在某一个宏任务执行完之后,就是在它执行之后把所有的微任务都会执行完(在渲染前)
microtask主要包含:Promise.then、MutaionObserver、process.nextTick(Node.js 环境)
运行机制
事件循环中,每进行一次循环都称为tick, 每一次tick 的任务处理模型是比较复杂的,但关键步骤如下:
- 执行一个宏任务(栈中没有就从事件队列中获取)
- 执行过程中如果到遇到微任务,就将它添加到微任务队列之中
- 宏任务执行完毕之后,立即检查当前微任务队列中所有的任务,若有依次执行
- 当宏任务执行完毕之后,开始检查渲染,然后GUI线程接管渲染
- 渲染完毕后,JS 线程继续接管,开始下一个宏任务(从事件队列中获取)
事件循环,宏任务,微任务的关系如图所示:
文章来源转载自:link.juejin.im/?target=htt…