前言:
刷面试题的意义在于,在一道题中把之前学到了知识点覆盖串联起来,加深印象,提高能力,而不是背答案。下面是一道字节跳动的面试题,可以复习到异步,promise,async/await,事件执行机制,宏任务微任务... 话不多说,直接上题:
题目:
function getJson() {
return new Promise((resolve, reject) => {
setTimeout(function() {
console.log(2);
resolve(2)
}, 2000)
})
}
async function testAsync() {
await getJson() //事件循环机制 await 下面的代码会去到下一次事件循环机制
console.log(3);
}
testAsync()
1. 输出结果是什么?
输出结果: 2 3
在事件循环机制中,await 下面的代码会去到下一次事件循环机制
2. async/await 原理是什么?
首先我们知道,async/await是ES7中的异步语法,我们可以从异步编程的发展史开始和面试官聊。 因为 JavaScript是单线程执行机制,所以为了提高效率我们使用异步编程。
异步编程的发展历史:
1. 回调函数:
缺点是不利于代码的阅读维护,各部分之间高度耦合,流程会很乱。每个人物只能指定一个回调函数。不能捕获异常 (try catch 同步执行,回调函数会加入队列,无法捕获错误)
2. Promise
Promise 不仅可以避免回调地狱,还可以统一捕获失败的原因,目前也应用广泛
3. Generator
生成器是一个函数,需要加* ,可以用来生成迭代器。生成器函数和普通函数不一样,普通函数是一旦调用一定会执行完,但是生成器函数中间可以暂停。生成器和普通函数不一样,调用它并不会立即执行。它会返回此生成器的迭代器,迭代器是一个对象,每调用一次next就可以返回一个值对象
4. co
随着前端的迅速发展,大神们觉得要像同步代码一样写异步,co问世了,co是 TJ 大神结合了promise 和 生成器 的一个库,实际上还是帮助我们自动执行迭代器
5. async/await
async await是语法糖,内部是generator+promise实现 async函数就是将Generator函数的星号(*)替换成async,将yield替换成await
事件执行机制: EventLoop
- 首先会执行同步操作
- 执行完后查看执行栈是否为空
- 如果为空,查看是否有微任务需要执行,如果有放入执行栈
- 在查看是否有宏任务需要执行,如果有放入执行栈
宏任务有哪些:
- script(整体代码)
- setTimeout
- setInterval
- I/O
- UI交互事件
- postMessage
- MessageChannel
- setImmediate(Node.js 环境)
微任务有哪些:
- Promise.then
- Object.observe
- MutaionObserver
- process.nextTick(Node.js 环境)
3. 将这段代码翻译成promise
当我们理解了async/await 就是语法糖,它的本质还是Promise,async相当于相当于Promise.then(),await相当于.then()括号里面的操作。所以翻译成Promise后就是下面这段代码:
// async function testAsync() {
// await getJson()
// console.log(3);
// }
//相当于:
function testAsync(){
return Promise.resolve().then(()=>{
return getJson()
}).then(()=>{
console.log(3);
})
}
参考文献:
1. 异步编程的前世今生