同步任务与异步任务
为了防止某个耗时任务导致程序假死的问题,JavaScript把待执行任务分为两类
同步任务(synchronous)
又叫做非耗时任务,指的是在主线程上排队执行的那些任务,只有等前一个任务执行完毕,才能执行后面一个任务。
异步任务
又叫做耗时任务,指的是由JavaScript委托给宿主环境进行执行的任务,当异步任务执行完成后,会通知JavaScript主线程执行异步任务的回调函数
异步任务又分为宏任务和微任务
宏任务(macrotask)
- 异步axja请求
- setTimeout,setInterval
- 文件操作
- 其他宏任务
微任务
- promise.then ,.catch ,.finally
- promise.nextTick(等DOM更新后,在进行组件更新操作)
- queueMicrotask微任务(和process.nextTick类似)
宏任务和微任务的执行顺序是,执行完同步任务,检查是否有微任务,当执行完微任务,再去执行下一个宏任务
面试题
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;
setTimeout为宏观任务,放到异步处理栈,调用async1(),输出async1 start,调用async2(),打印async2,await用于等待一个promise返回对象,而promise.then是一个微任务,而微任务要等所有的同步任务完成才能执行,那么继续往下看有没有未完成的同步任务,输出promise1,script end 然后promise.then返回完成,执行后面的操作,打印 async1 end,同步任务执行完后,继续看执行完的同步任务中是否有回调函数未执行,也就是微任务,然后打印promise2 ,最后所有微任务执行完,再执行宏任务,打印setTimeout
注意点
- 执行顺序,一定是先同步,再执行宏任务之前,检查是否有待执行的微任务
async和await
async的返回值期待一个实现thenable接口的对象,但是常规的值也可以。await关键字可以暂停异步函数代码的执行,等到await右边的值,Javascript运行时会像消息队列推送一个任务,这个任务会恢复异步函数的执行,即使await后面跟着一个立即可用的值,函数的其余部分也会被异步求值,所以要等所有的同步任务被执行完,才能执行。对于 async和await及promise还需深入了解