在 JS 中, 基本上来说 有 三种 异步操作
[MicroTask] MicroTask 是 当前 执行 的 Task 结束后立即执行的 工作(work). MicroTask 不可取消以保证只执行一次并且在 当前 Task 结束后立即执行。
[MacroTask] MacroTask 用于 稍后要执行的工作, 比如
setTimeout
.
MacroTask 通常是可以取消的, 在一定的延迟过后至少会执行一次。
怎么理解这句话呢?
拿setTimeout
来说,
var timer = setTimeout(function fn(){
console.log('timeout after 5000 delay');
}, 5000);
如果 5000ms 之内, 我们可以 执行
clearTimeout(timer);
这样函数 fn 就不会再执行, MacroTask fn 也就取消了。但是如果没有取消操作的话, 就会执行函数 fn, 这里 函数 fn 会执行一次。
- [EventTask] 用来 监听 未来的 事件。在某个未知的延迟之后 会 执行 0次或者多次
摘录:
* A JS VM can be modeled as a [MicroTask] queue, [MacroTask] queue, and [EventTask] set.
*
* - [MicroTask] queue represents a set of tasks which are executing right after the current stack
* frame becomes clean and before a VM yield. All [MicroTask]s execute in order of insertion
* before VM yield and the next [MacroTask] is executed.
* - [MacroTask] queue represents a set of tasks which are executed one at a time after each VM
* yield. The queue is ordered by time, and insertions can happen in any location.
* - [EventTask] is a set of tasks which can at any time be inserted to the end of the [MacroTask]
* queue. This happens when the event fires.
从中可得知:
MicroTask 的执行时机或者执行条件:
1、 执行栈为空, 也就是 Execution Context Stack 里不再有栈帧。
且 在 VM yield 之前
2、下一个 MacroTask 执行之前
MicroTask 执行顺序: 按照 插入队列的顺序执行。MacroTask 执行时机:
每次 VM yield 之后,每次执行一个 MacroTask
MacroTask 队列是按照时间排序的, 并且 MacroTask的插入可以在任何位置EventTask 发生时机: 触发事件
EventTask 可以在任何时间插入到 MacroTask 队列尾。
references:
https://github.com/angular/zone.js/blob/master/dist/zone.js.d.ts