- 前言:
关于js异步执行顺序,宏任务、微任务这些,还有async/await已经有好多人写了。但是每个人都有自己的理解,最主要的是要自己琢磨,学习了一下,谈谈自己的理解。
先上一张图压压惊!!!
微任务与宏任务区别,纯白话理解:
这个就像是去银行办理业务,得先排队取号。我们可以把每个办理业务的人当做是一个宏任务的存在。那么多个宏任务合在一起,可以说这就是一个任务队列。
那么微任务是什么呢?一个宏任务在执行的过程中,是可以添加一些微任务的。
那么微任务是什么呢?举个例子:
就像在柜台办理业务,你前边的一位老大爷可能在存款,在存款这个业务办理完以后,柜员会问老大爷还有没有其他需要办理的业务,这时老大爷想了一下:“要理财,我要发财,哈哈”,然后告诉柜员说,要办一些理财的业务,这时候柜员肯定不能告诉老大爷说:“您再上后边取个号去,重新排队吧”。
所以本来快轮到你来办理业务,会因为老大爷临时添加的“理财业务”而往后推。而这些临时发生的我们可以认为就是微任务!
再次说明:你大爷永远是你大爷!吼吼 在当前的微任务没有执行完成时,是不会执行下一个宏任务的。所以就有了以下类似面试题:
setTimeout(()=>{
console.log('1');
},0) // 放置任务队列 -- 宏任务
new Promise((resolve, reject)=>{
console.log('2');
// 同,这里注意promise是用来管理异步操作,本身非异步
reject() // 结果回调
}).then(value=> { // 微任务
console.log('3');
}, reason => {
console.log('5');
setTimeout(()=> {
console.log('6');
})
})
console.log('4');
// 2,4,5,1,6
我们可以认为任务队列执行优先级: 同步 > 微任务 > 宏任务
async && await
- async 是什么,做什么的?
- await 从字面拆分来看,等待,它在等什么?
1、async
async function fn1() {
return 123
}
function fn2() {
return 123
}
console.log(fn1()) // Promise {<fulfilled>: 123}
console.log(fn2()) // 123
直观来看,async 无非就是把return值用Promise.resolve()包装了一下。
注:
- 语义上理解,async表示函数内部有异步操作
- await要写在async函数内部,否则报错
2、await
await 在等什么?一句话概括:await等的是右侧【表达式】的结果
等到之后,对于await来说要做什么?分情况
- 不是promise对象
- 是promise对象
async function async1() {
console.log( 'async1 start' )
await async2()
console.log( 'async1 end' ) // await async2()阻塞了它
}
async function async2() {
console.log( 'async2' )
}
async1()
console.log( 'script start' ) // 同步
// async1 start async2 script start async1 end
这里注意一点,可能大家都知道await会让出线程,阻塞后面的代码,那么上面例子中, ‘async2’ 和 ‘script start’ 谁先打印呢?
是从左向右执行,一旦碰到await直接跳出, 阻塞async2()的执行?
还是从右向左,先执行async2后,发现有await关键字,于是让出线程,阻塞代码呢?
实践的结论是: 从右向左的。先打印async2,后打印的script start
之前说的await等到,做什么分两种情况:
- 如果等到表达式值非 promise ,表达式值将进入队列,await阻塞后面代码,先执行async外面的同步代码 ,同步代码执行完,再回到async内部,把这个非promise的东西,作为 await表达式的结果
- 如果它等到的是一个 promise 对象,表达式值不会进入队列,await 也会暂停async后面的代码,先执行async外面的同步代码,等着 Promise 对象 fulfilled,然后把 resolve 的参数作为 await 表达式的运算结果。
async function async1() {
console.log( 'async1 start' )
await async2()
console.log( 'async1 end' )
}
async function async2() {
// console.log( 'async2' )
return new Promise(resolve=>{
resolve()
}).then(value=>{
console.log('微任务');
})
}
async1()
console.log( 'script start' )
打印结果: async start1 script start 微任务 async1 end
上述代码改造,打印结果就会发生变化。细品
最后看一道以前「今日头条」类似面试题:
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(function () {
console.log('setTimeout');
}, 0)
async1();
new Promise(function (resolve) {
console.log('promise1');
resolve();
}).then(function () {
console.log('promise2');
});
console.log('script end');
// script start async1 start async2 promise1 script end async1 end promise2 setTimeout
你过关了吗!!!每个人的理解说得都不一定准确,只能自己多思考了。
辅助功法传送门:👇
1、async/await讲解
2、阮老师promise讲解