JavaScript 执行机制
1.同步任务、异步任务、宏任务、微任务
同步任务:指的是在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务
异步任务:指的是不进入主线程、而进入"任务队列"(task queue)的任务
宏任务:script(主程序代码) setTimeOut setInterVal setImmediate I/O操作 UI渲染 requestAnimationFrame
微任务:promise(原生) MutationObserver process.nextTick() mutation Object.observe
2.优先级(执行顺序)
主程序代码(宏任务) > process.nextTick > Promise(微任务)> setTimeout(fn)、setInterval(fn)(宏任务)> setImmediate(宏任务)> I/O——>UI rendering
I/O: mouse clicks 、keypresses、network events
3.javascript事件循环
导图要表达的内容用文字来表述的话:
1.同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table(事件表)并注册函数。
2.当指定的事情完成时,Event Table会将这个函数移入Event Queue。
3.主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。
4.上述过程会不断重复,也就是常说的Event Loop(事件循环)。
例子一:
let data = [];
$.ajax({
url:www.javascript.com,
data:data,
success:() => {
console.log('发送成功!');
}
})
console.log('代码执行结束');复制代码上面是一段简易的ajax请求代码:
- ajax进入Event Table,注册回调函数success。
- 执行console.log(‘代码执行结束’)。
- ajax事件完成,回调函数success进入Event Queue。
- 主线程从Event Queue读取回调函数success并执行。
例子二:
setTimeout(function() {
console.log('setTimeout');
})
new Promise(function(resolve) {
console.log('promise');
}).then(function() {
console.log('then');
})
console.log('console');
- 这段代码作为宏任务,进入主线程。
- 先遇到setTimeout,那么将其回调函数注册后分发到宏任务Event Queue。(注册过程与上同,下文不再描述)
- 接下来遇到了Promise,new Promise立即执行,then函数分发到微任务Event Queue。
- 遇到console.log(),立即执行。
- 好啦,整体代码script作为第一个宏任务执行结束,看看有哪些微任务?我们发现了then在微任务Event Queue里面,执行。
- ok,第一轮事件循环结束了,我们开始第二轮循环,当然要从宏任务Event Queue开始。我们发现了宏任务Event Queue中setTimeout对应的回调函数,立即执行。
- 结束。
备注:setTimeout(fn,ms),其中setTimeout并不是ms时间后fn执行,而是ms时间后setTimeout将其回调函数注册后分发到宏任务Event Queue(事件队列)
4.事件循环,宏任务,微任务的关系
实例
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(宏任务输出1 7,微任务输出6 8)
- 第二轮事件循环正式结束,输出结果2 4 3 5(宏任务输出2 4,微任务输出3 5)
- 第三轮事件循环正式结束,输出结果9 11 10 12(宏任务输出9 11,微任务输出10 12)
- 整段代码,共进行了三次事件循环,完整的输出为1,7,6,8,2,4,3,5,9,11,10,12。
(请注意,node环境下的事件监听依赖libuv与前端环境不完全相同,输出顺序可能会有误差)
备注:源文参考地址 https://juejin.im/post/59e85eebf265da430d571f89
5.写在最后
- javascript是一门单线程语言
- Event Loop是javascript的执行机制