event-loop

一些异步事件

window.setImmediate

该方法用来把一些需要长时间运行的操作放在一个回调函数里,在浏览器完成后面的其他语句后,就立刻执行这个回调函数,

1
2
3
> var immediateID = setImmediate(func, [param1, param2, ...]);
> var immediateID = setImmediate(func);
>

immediateID 是这次setImmediate方法设置的唯一ID,可以作为 window.clearImmediate 的参数.
func 是将要执行的回调函数

参数param1 param2 …都会直接传给函数func

window.clearImmediate 用来取消通过setImmediate设置的将要执行的语句

与setTimeout

1
2
3
4
5
6
7
8
9
10
setTimeout(() => {
console.log('timeout');
}, 0);

setImmediate(() => {
console.log('immediate');
});
// 输出
// immediate
// timeout
  • setImmediate() 设计为在当前 轮询 阶段完成后执行脚本。
  • setTimeout() 计划在毫秒的最小阈值经过后运行的脚本。

process.nextTick

无论事件循环的当前阶段如何,都将在当前操作完成后处理 nextTickQueue

  • process.nextTick() 在同一个阶段立即执行。
  • setImmediate() 在以下迭代或 ‘tick’ 上触发事件循环。

使用时机:

  1. 允许用户处理错误,清理任何不需要的资源,或者在事件循环继续之前重试请求。
  2. 有时在调用堆栈已解除但在事件循环继续之前,必须允许回调运行。

useMutationObserver

MutationObserver接口提供了监视对DOM树所做更改的能力。它被设计为旧的Mutation Events功能的替代品,该功能是DOM3 Events规范的一部分。

构造函数 MutationObserver()
创建并返回一个新的 MutationObserver 它会在指定的DOM发生变化时被调用。

很多框架和库都会使用类似下面函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
function flush() {
console.log('MutationObserver')
}
function useMutationObserver() {
var iterations = 0;
var observer = new MutationObserver(flush);
var node = document.createTextNode('');
observer.observe(node, { characterData: true });

return function () {
node.data = iterations = ++iterations % 2;
};
}

使用Mutation事件可以异步执行操作(例子中的flush函数),一是可以尽快响应变化,二是可以去除重复的计算

异步

一个🌰看看, 这些异步是怎么执行的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
console.log('start')

setTimeout( function () {
console.log('setTimeout')
}, 0 )
setImmediate(() => {
console.log('immediate');
}); // 只在chrome中可以调用

Promise.resolve().then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});
useMutationObserver()()

console.log('end')

// chrome执行顺序:
// start
// end
// promise1
// MutationObserver
// promise2
// immediate
// setTimeout

任务

事件轮训是实现异步的一种方式

任务

一个事件轮训有一个或多个任务队列

每当要执行一个任务时, 必须将这个任务添加到相应的事件轮训队列中

每一个任务都来自于特定的任务源, 被添加到特定的任务队列

任务源

任务源种类:

  • DOM操作任务源
  • 用户交互任务源
  • 网络任务源
  • history traversal任务源

task任务源非常宽泛,比如ajax的onload,click事件,基本上我们经常绑定的各种事件都是task任务源,还有数据库操作(IndexedDB ),需要注意的是setTimeout、setInterval、setImmediate也是task任务源。

总结来说task任务源:

​ setTimeout
​ setInterval
​ setImmediate
​ I/O
​ UI rendering

微任务

每一个事件轮训, 都有一个微任务队列, 微任务会被排进微任务队列

微任务有两种: 1.孤立回调微任务 2.复合微任务(不做考虑)

microtask 队列和task 队列有些相似,都是先进先出的队列,由指定的任务源去提供任务,不同的是一个
event loop里只有一个microtask 队列。

通常认为是microtask任务源有:

  • process.nextTick
  • promises
  • Object.observe
  • MutationObserver