event loop 决定js代码的执行顺序为了协调事件,用户交互,脚本,渲染,网络等
当用户代理安排一个任务,必须将该任务增加到相应的event loop的一个tsak队列中。
每一个task都来源于指定的任务源,比如可以为鼠标、键盘事件提供一个task队列,其他事件又是一个单独的队列。可以为鼠标、键盘事件分配更多的时间,保证交互的流畅。
task也被称为macrotask,是一个先进先出的队列,由指定的任务源去提供任务。
task/macrotask任务源:
- setTimeout
- setInterval
- setImmediate
- I/O
- UI rendering
microtask 队列和task 队列有些相似,都是先进先出的队列,由指定的任务源去提供任务,不同的是一个
event loop里只有一个microtask 队列。
microtask任务源:
- process.nextTick
- promises
- Object.observe
- MutationObserver
event loop的循环过程:
- 在tasks队列中选择最老的一个task,用户代理可以选择任何task队列,如果没有可选的任务,则跳到下边的microtasks步骤。
- 将上边选择的task设置为正在运行的task。
- Run: 运行被选择的task。
- 将event loop的currently running task变为null。
- 从task队列里移除前边运行的task。
- Microtasks: 执行microtasks任务检查点。(也就是执行microtasks队列里的任务)
- 更新渲染(Update the rendering)...
- 如果这是一个worker event loop,但是没有任务在task队列中,并且WorkerGlobalScope对象的closing标识为true,则销毁event loop,中止这些步骤,然后进行定义在Web workers章节的run a worker。
- 返回到第一步。
概括:
microtasks检查点(microtask checkpoint)
- 将microtask checkpoint的flag设为true。
- Microtask queue handling: 如果event loop的microtask队列为空,直接跳到第八步(Done)。
- 在microtask队列中选择最老的一个任务。
- 将上一步选择的任务设为event loop的currently running task。
- 运行选择的任务。
- 将event loop的currently running task变为null。
- 将前面运行的microtask从microtask队列中删除,然后返回到第二步(Microtask queue handling)。
- Done: 每一个environment settings object它们的 responsible event loop就是当前的event loop,会给environment settings object发一个 rejected promises 的通知。
- 清理IndexedDB的事务。
- 将microtask checkpoint的flag设为flase。
task和microtask都是推入栈中执行的,
主线程类似一个加工厂,它只有一条流水线,待执行的任务就是流水线上的原料,只有前一个加工完,后一个才能进行。event loops就是把原料放上流水线的工人。只要已经放在流水线上的,它们会被依次处理,称为同步任务。一些待处理的原料,工人会按照它们的种类排序,在适当的时机放上流水线,这些称为异步任务。
setTimeout(function() {
console.log('setTimeout');
})
new Promise(function(resolve) {
console.log('promise');
}).then(function() {
console.log('then');
})
console.log('console');
task:script microtask:
取出script推入栈中执行,promise立即执行以及打印
settimeout为task,then为microtask
【task队列:settimeout;microtask队列:then】
执行microtask,进行下一项
从task队列取出settimeout,推入栈中执行
console.log('1');
setTimeout(function() {
console.log('2');
process.nextTick(function() {
console.log('3');
})
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
process.nextTick(function() {
console.log('6');
})
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('9');
process.nextTick(function() {
console.log('10');
})
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})
task:script microtask:
取出script推入栈中执行,打印1,setTimeout为task,nextTick为microtask,打印7,then为microtask,setTimeout为task
【task队列:settimeout1 setTimeout2 ;microtask队列:nextTick then】
执行microtask打印6以及8,进行下一项
【task队列:setTimeout1 setTimeout2;microtask队列:】
从task队列取出settimeout1,推入栈中执行,打印2,setTimeout-nextTick为microtask,立即执行Promise打印4,setTimeout-then为microtask
【task队列:setTimeout2;microtask队列: setTimeout-nextTick setTimeout-then】
执行microtask打印3以及5,进行下一项
【task队列:setTimeout2;microtask队列:】
从task队列取出settimeout2,推入栈中执行,打印9,setTimeout2-nextTick为microtask,立即执行Promise打印11,setTimeout2-then为microtask
【task队列:;microtask队列:setTimeout2-nextTick setTimeout2-then】
打印打印10,打印12
网友评论