微任务_宏任务
代码
下面可执行代码, 按什么顺序执行呢?
同步_异步
同步代码: 执行顺序和书写顺序一致
异步代码: 不是立即执行的,执行顺序和书写顺序不一致。
js中典型的异步代码有:
- 定时器:setTimeout,setInterval
- Ajax
- dom事件 但实际上, js是一门单线程语言, 他是怎么实现异步的呢?
事件循环Event Loop
js是单线程的,一次只能做一件事。js在浏览器这个宿主环境中运行。浏览器是多线程的,用户交互,定时器,网络请求等等浏览器中的事件会产生对应的任务,任务多了要在任务队列中排队,浏览器的主线程依次取出任务来执行,此过程不断重复从而形成一个循环,称为eventLoop。
微任务_宏任务
异步任务也有优先级区分,优先级高的叫微任务,相对低的是宏任务 不是马上执行,是放入到队列中等待;
如果所有的任务都要按序等待,那么也不行,需要有一个能插队的机制。所以又将异步任务分为微任务和宏任务,同时对应微任务队列和宏任务队列。
当主线程空闲时,先执行微任务队列中的任务,再去执行宏任务队列中的任务。
微任务代码(js语法)
- Promise对象.then()
宏任务代码(宿主环境)
- script
- dom事件
- ajax
- setTimout
示例
<script>
1 console.log(1);
2 async function fnOne() {
console.log(2);
await fnTwo();
console.log(3);
}
3 async function fnTwo() {
console.log(4);
}
4 fnOne();
5 setTimeout(() => {
console.log(5);
}, 2000);
6 let p = new Promise((resolve, reject) => {
console.log(6);
resolve();
console.log(7);
})
7 setTimeout(() => {
console.log(8)
}, 0)
8 p.then(() => {
console.log(9);
})
9 console.log(10);
</script>
分析:
a. script首当其冲,进入宏任务队列.开始执行script内代码.
b. 1行同步代码直接打印1 =>
2行代码为函数定义,不执行 =>
3行也是定义 => 4行开始执行fnOne函数 =>
进入2行,打印2,await fnTwo()执行fnTwo,进入3,打印4,由于await阻塞了当前函数的下面代码块运行, 所以console.log(3)放入微任务队列 =>
5行 放入宏任务 =>
6行 new 关键字同步执行,打印6,返回fullfilled状态的promise对象,值undefined, 打印7 =>
7行放入宏任务队列,但他是0s后执行,比5定时器快,所以排在前面 =>
8行 因为p上面得状态fullfilled,所以then执行,放入微任务队列 =>
9行 打印10
***b结果:结果:1 2 4 6 7 10 ***
c. 上面script的宏任务已经完成
(右边优先)
微任务队列有: log(9) log(3)
宏任务队列有: log(5) 2s log(8) 0s
先执行微任务队列, 随后执行宏任务队列 输出:3 9 8 5
最终打印结果为: 1 2 4 6 7 10 3 9 8 5