Appearance
JS执行机制
一 单线程
- JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事
- JavaScript作为浏览器脚本语言,主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题
- 尽管为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质
二 任务类型
- 任务分为:同步任务和异步任务
流程图

说明
- 同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册函数
- 当指定的事情完成时,Event Table会将这个函数移入Event Queue
- 主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行
- 上述过程会不断重复,也就是常说的Event Loop(事件循环)
- 补充:js引擎存在monitoring process进程,会持续不断的检查主线程执行栈是否为空,一旦为空,就会去Event Queue那里检查是否有等待被调用的函数
示例
js
$.ajax({
url: url,
data:{},
success:() => {
console.log('发送成功!');
}
})
console.log('代码执行结束');- ajax进入Event Table,注册回调函数success。
- 执行
console.log('代码执行结束')。 - ajax事件完成,回调函数success进入Event Queue。
- 主线程从Event Queue读取回调函数success并执行。
三 队列类型
- 异步任务-也叫异步队列分为:宏队列和微队列
原理图

具体说明
- JS 中用来存储待执行回调函数的队列包含 2 个不同特定的列队
- 宏列队:用来保存待执行的宏任务(回调),比如:定时器回调、DOM 事件回调、ajax 回调
- 微列队:用来保存待执行的微任务(回调),比如:promise的回调、MutationObserver 的回调
- JS 执行时会区别这 2 个队列
- JS 引擎首先必须先执行所有的初始化同步任务代码
- 每次准备取出第一个宏任务执行前, 都要将所有的微任务一个一个取出来执行
优先级
sh
同步任务 > 微任务 > 宏任务常见分类
- 宏任务
js
script(整体代码)
setTimeout
setInterval
setImmediate
I/O 操作等
requestAnimationFrame- 微任务
js
process.nextTick
new Promise().then(回调) | catch | finally
MutationObserver四 测试题
js
console.log(1);
async function async () {
console.log(2);
await console.log(3);
console.log(4)
await async2();
console.log(5)
}
async function async2() {
console.log(6);
}
setTimeout(() => {
console.log(7);
}, 0);
const promise = new Promise((resolve, reject) => {
console.log(8);
resolve(9)
})
promise.then(res => {
console.log(res)
})
async();
console.log(10);
// 1 8 2 3 10 9 4 6 5 7