之前翻译过一片关于Event Loop的文章,有了一个简单的了解,那么浏览器中的Event Loop和Node中有什么区别呢,下面用几个示例来探究下。
首先收悉一下之前的概念:
task任务:setTimeout setInterval setImmediate I/O UI交互事件
microtask微任务:Promsie process.nextTick MutaionObserver
再次放上一张经典的图(Node)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| ┌───────────────────────┐ ┌─>│ timers │ │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ │ │ I/O callbacks │ │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ │ │ idle, prepare │ │ └──────────┬────────────┘ ┌───────────────┐ │ ┌──────────┴────────────┐ │ incoming: │ │ │ poll │<─────┤ connections, │ │ └──────────┬────────────┘ │ data, etc. │ │ ┌──────────┴────────────┐ └───────────────┘ │ │ check │ │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ └──┤ close callbacks │ └───────────────────────┘
|
setTimeout setInterval
这两个在浏览器和Node的功效是一样的,意思都是过一定的时间段后执行或者循环某些函数。
这是Node中独有的操作,功效和setTimeout差不多,差别在于
process.nextTick
简单来讲
测试0:
1 2 3 4 5 6 7 8 9 10 11 12 13
| setTimeout(() => { console.log('1'); process.nextTick(()=>{ console.log('2'); }) });
setTimeout(() => { console.log('3'); process.nextTick(()=>{ console.log('4'); }) })
|
测试1:
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 27 28
| console.log(1)
setTimeout(() => { console.log(2) new Promise(resolve => { console.log(4) resolve() }).then(() => { console.log(5) }) })
new Promise(resolve => { console.log(7) resolve() }).then(() => { console.log(8) })
setTimeout(() => { console.log(9) new Promise(resolve => { console.log(11) resolve() }).then(() => { console.log(12) }) })
|
浏览器执行如下:
- 同步运行的代码首先输出:1、7
- 接着,清空microtask队列:8
- 第一个task执行:2、4
- 接着,清空microtask队列:5
- 第二个task执行:9、11
- 接着,清空microtask队列:12
node执行如下:
1 7 8 2 4 9 11 5 12
node执行下是先执行所有的setTimeout,在处理microtask队列
测试2:
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
| console.log(1)
setTimeout(() => { console.log(2) new Promise(resolve => { console.log(4) resolve() }).then(() => { console.log(5) }) process.nextTick(() => { console.log(3) }) })
new Promise(resolve => { console.log(7) resolve() }).then(() => { console.log(8) })
process.nextTick(() => { console.log(6) })
|
输出1 7 6 8 2 4 3 5
说明Promise和process.nextTick虽然同时属于微任务,但是Promise的优先级较低
测试3:
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 27 28 29 30 31 32 33 34 35 36 37 38
| console.log(1)
setTimeout(() => { console.log(2) new Promise(resolve => { console.log(4) resolve() }).then(() => { console.log(5) }) process.nextTick(() => { console.log(3) }) })
new Promise(resolve => { console.log(7) resolve() }).then(() => { console.log(8) })
process.nextTick(() => { console.log(6) })
setTimeout(() => { console.log(9) process.nextTick(() => { console.log(10) }) new Promise(resolve => { console.log(11) resolve() }).then(() => { console.log(12) }) })
|
输出1 7 6 8 2 4 9 11 3 10 5 12
测试4:
1 2 3 4 5 6 7 8 9 10 11 12
| setTimeout(() => { console.log(2) }, 2)
setTimeout(() => { console.log(1) }, 1)
setTimeout(() => { console.log(0) }, 0)
|
在node下输出结果有时候为 1 2 0,2 1 0,1 0 2(为什么呢)
在浏览器下出输出结果为1 0 2
Node Event Loop
- expired timers and interval
- I/O events
- immediates
- close handlers
同步任务及每个阶段都会清空microtask微任务
- next tick queue (process.nextTick)
- other queue (Promise)