网站开发 发票哈尔滨推广优化公司
Javascript 有一个 main thread 主线程和 call-stack 调用栈(执行栈),所有的任务都会被放到调用栈等待主线程执行。
同步任务会在调用栈中按照顺序等待主线程依次执行
异步任务会先进入Event Table并注册函数,当指定的事情完成后,Event Table会将注册的回调函数放入移入Event Queue,等待主线程空闲的时候(调用栈被清空),被读取到栈内等待主线程的执行。
宏任务 MacroTask:script全部代码、setTimeout、setInterval、setImmediate(浏览器暂时不支持,只有IE10支持,具体可见MDN)、I/O、UI Rendering。
重点是前三个
微任务 MicroTask:Promise、Process.nextTick(Node独有)、Object.observe(废弃)、MutationObserver
重点是第一个,process.nextTick(callback)类似node.js版的‘setTimeout’,在事件循环的下一次循环中调用callback回调函数
使用await时,解释器都创建一个promise对象,然后把剩下的async函数中的操作放到then回调函数中。
1 事件循环
执行栈在执行完同步任务后,查看执行栈是否为空
如果执行栈为空,就会去检查微任务队列是否为空
微任务队列不为空就一次性执行完所有微任务
微任务队列为空的话,就执行宏任务
每次单个宏任务执行完毕后,检查微任务队列是否为空,如果不为空的话,会按照先入先出的规则全部执行完微任务后,设置微任务队列为null,然后再执行宏任务,如此循环。
2 setTimeout
setTimeout(() => {task()
},3000)sleep(10000000)
控制台执行task()需要的时间远远超过3秒,因为:
task()进入Event Table并注册,计时开始。
执行sleep函数,很慢,非常慢,计时仍在继续。
3秒到了,计时事件timeout完成,task()进入Event Queue,但是sleep也太慢了吧,还没执行完,只好等着。
sleep终于执行完了,task()终于从Event Queue进入了主线程执行。
这个例子很好的解释了setTimeout的运行机制
所以setTimeout这个函数,是经过指定时间后,把要执行的任务(本例中为task())加入到Event Queue中,又因为是单线程任务要一个一个执行,如果前面的任务需要的时间太久,那么只能等着,导致真正的延迟时间远远大于3秒。
setTimeout(fn,0)的含义是,指定某个任务在主线程最早可得的空闲时间执行,意思就是不用再等多少秒了,只要主线程执行栈内的同步任务全部执行完成,栈为空就马上执行。(但不代表没有延迟)
3 setInterval
setInterval会每隔指定的时间将注册的函数置入Event Queue,如果前面的任务耗时太久,那么同样需要等待。
(不一定是每隔指定时间执行一次,一旦setInterval注册的回调函数执行时间超过了延迟时间,那么就完全看不出来有时间间隔了)
4 题目
setTimeout(function() {console.log('setTimeout');
})new Promise(function(resolve) {console.log('promise');
}).then(function() {console.log('then');
})console.log('console');
这题有个小bug,promise里面没有resovle(),所以不会执行then
输出:promise,console,setTimeout
setTimeout(function() {console.log('setTimeout');
})new Promise(function(resolve) {console.log('promise');resolve();
}).then(function() {console.log('then');
})console.log('console');
输出:promise,console,then,setTimeout
console.log('script start');setTimeout(function() {console.log('setTimeout');
}, 0);Promise.resolve().then(function() {console.log('promise1');
}).then(function() {console.log('promise2');
});
console.log('script end');
输出:script start,script end,promise1,promise2,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')})
})
输入: 1,7,6,8,2,4,3,5,9,11,10,12
console.log('script start')async function async1() {await async2()console.log('async1 end')
}
async function async2() {console.log('async2 end')
}
async1()setTimeout(function() {console.log('setTimeout')
}, 0)new Promise(resolve => {console.log('Promise')resolve()
}).then(function() {console.log('promise1')}).then(function() {console.log('promise2')})console.log('script end')
输出:script start,async2 end,Promise,script end,async1 end,promise1,promise2,setTimeout
参考:https://juejin.cn/post/6844903512845860872
https://juejin.cn/post/6844903764202094606#heading-13