-
js是单线程的,该线程中有唯一一个事件循环,任务队列可以有多个
-
JavaScript代码的执行过程中,除了依靠函数调用栈来搞定函数的执行顺序外,还依靠任务队列(task queue)来搞定另外一些代码的执行。
队列数据结构 -
任务队列: 宏任务和微任务
- 宏任务:script(整体代码)、setTimeout、setInterval、setImmediate、(I/O、UI rendeing这俩没研究)
- 微任务:Promise、Node中的process.nextTick、html5新特性MutationObserver(没研究)
- setTimeout/Promise等我们称之为任务源(任务分发器)。而进入任务队列的是他们指定的具体执行任务。
- 来自不同任务源的任务会进入到不同的任务队列。其中setTimeout与setInterval是同源的。
- 其中每一个任务的执行,无论是macro-task还是micro-task,都是借助函数调用栈来完成。
关于setImmediate:MDN解释
- 该特性是非标准的,请尽量不要在生产环境中使用它!
- 该方法用来把一些需要长时间运行的操作放在一个回调函数里,在浏览器完成后面的其他语句后,就立刻执行这个回调函数。
- 注意: 该方法可能不会被批准成为标准,目前只有最新版本的 Internet Explorer 和Node.js 0.10+实现了该方法。它遇到了 Gecko(Firefox) 和Webkit(Google/Apple) 的阻力。
浏览器执行
console.log('global1')
setTimeout(() => {
console.log('setTimeout1')
new Promise(resolve => {
console.log('p1')
resolve()
})
.then(() => {
console.log('p1-then')
})
new Promise(resolve => {
console.log('p2')
resolve()
})
.then(() => {
console.log('p2-then')
})
})
setTimeout(() => {
console.log('setTimeout2')
new Promise(resolve => {
console.log('p3')
resolve()
})
.then(() => {
console.log('p3-then')
})
})
new Promise(resolve => {
console.log('p5')
resolve()
})
.then(() => {
console.log('p5-then')
})
console.log('global2')
输出顺序:
// global1 p5 global2 p5-then setTimeout1 p1 p2 p1-then p2-then setTimeout2 p3 p3-then
浏览器执行机制:
- script (这个过程中执行同步代码,宏任务加入相应类型的队列,微任务加入相应类型的队列)
- 执行清空所有微任务
- 执行第一个加入队列的宏任务 setTimeout (setImmediate的任务队列会在setTimeout队列的后面执行),并将该过程中产生的微任务加入相应的队列
- 执行清空所有微任务
- 执行第二个宏任务
...
以此类推,以一个宏任务---所有微任务的顺序交替执行
Node执行
console.log('global1')
setImmediate(() => {
console.log('setImmediate1')
new Promise(resolve => {
console.log('p1')
resolve()
})
.then(() => {
console.log('p1-then')
})
})
setTimeout(() => {
console.log('setTimeout1')
new Promise(resolve => {
console.log('p2')
resolve()
})
.then(() => {
console.log('p2-then')
})
new Promise(resolve => {
console.log('p3')
resolve()
})
.then(() => {
console.log('p3-then')
})
})
setTimeout(() => {
console.log('setTimeout2')
new Promise(resolve => {
console.log('p4')
resolve()
})
.then(() => {
console.log('p4-then')
})
process.nextTick(() => {
console.log('process1')
})
})
new Promise(resolve => {
console.log('p5')
resolve()
})
.then(() => {
console.log('p5-then')
})
process.nextTick(() => {
console.log('process2')
})
console.log('global2')
Node输出:
// global1 p5 global2 process2 p5-then setTimeout1 p2 p3 setTimeout2 p4 process1 p2-then p3-then p4-then setImmediate1 p1 p1-then
Node执行机制:
- 同浏览器
- 执行清空所有微任务 (执行微任务时,nextTick队列会比Promie先执行。nextTick中的可执行任务全部执行完毕之后,才会开始执行Promise队列中的任务。)
- 执行某一类(某一队列)宏任务(先执行完所有setTimeout宏任务,将该过程产生的微任务加入相应队列)
- 执行清空所有微任务
- 执行另一队列宏任务 setImmediate
...
以此类推,以一类(队列)宏任务---所有微任务的顺序交替执行。
网友评论