前端JS面试题-进阶-异步
本文主要包括如下内容:
- event loop
- async / await
- 微任务 宏任务
题目:
- 请描述event loop(事件循环/事件轮询)的机制,可画图
- 什么是宏任务和微任务,两者有什么区别
- promise有哪三种状态,如何变化
- 场景题,promise then 和 catch 的链接
- 场景题 async/await语法
- 场景题 promise 和 setTImeout的打印顺序
- 场景题 外加async/await的顺序问题
1. 请描述event loop(事件循环/事件轮询)的机制
- 同步代码,一行一行放在 call stack 【主执行栈】 执行
- 遇到异步,会先“记录”下,等待时机(定时、网络请求等)
- 时机到了,就将该异步事件移动到 callback queue 【回调队列】
- 一旦同步代码执行完, call stack 空了,就会立刻执行 event loop 机制(引擎启动)
- event loop 不断循环 callback queue,如有则移动到call stack 执行
- 然后继续轮询查找
2. 什么是宏任务和微任务,两者有什么区别
- 宏任务:setTimeout setInterval Ajax DOM事件;DOM 渲染后触发
- 微任务:promise async/await;DOM渲染前触发
- 因此,微任务执行时机比宏任务要早
3. promise有哪三种状态,如何变化
4. 场景题,promise then 和 catch 的链接
- 第一题: 1 3
- 第二题: 1 2 3
- 第三题: 1 2
5. 场景题 async/await语法
- 执行async 函数,返回的是promise对象
- await相当于promise的then,处理不了catch
- 左侧题目:
a 是 promise
b 是 100 - 右侧题目 打印顺序
a 100
b 200
报错
6. 场景题 promise 和 setTImeout的打印顺序
100 400 300 200
- 先执行同步代码,再执行异步代码
- 先执行微任务,再执行宏任务
7. 场景题 外加async/await的顺序问题
async function async1() {
console.log('async1 start') // 2
await async2()
// await 后面地都作为回调内容 —— 微任务
console.log('async1 end') // 6
}
async function async2() {
console.log('async2') // 3
}
console.log('script start') // 1
setTimeout(function () { //宏任务
console.log('setTimeout') // 8
}, 0)
async1()
// 初始化 promise 时,传入地函数会立刻被执行
new Promise (function (resolve) {
console.log('promise1') // 4
resolve()
}).then (function () { // 微任务
console.log('promise2') // 7
})
console.log('script end') // 5
同步代码执行完毕(event loop — call stack 被清空)
执行微任务
尝试触发 DOM 渲染
触发 event loop,执行宏任务
知识点
1.JS如何执行
- 从前到后,一行一行执行
- 如何某一行执行报错,则停止下面代码的执行
- 先把同步代码执行完,再执行异步
console.log('hi')
setTimeout(function cb1() {
console.log('cb1)
}, 5000)
console.log('bye)
// 打印顺序: hi bye cb1
2. event loop 事件循环/事件轮询
- JS是单线程运行的
- 异步要基于回调来实现
- event loop 就是异步回调的实现原理
3. event loop 的执行过程
- 同步代码,一行一行放在 call stack 【主执行栈】 执行
- 遇到异步,会先“记录”下,等待时机(定时、网络请求等)
- 时机到了,就将该异步事件移动到 callback queue 【回调队列】
- 一旦同步代码执行完, call stack 空了,就会立刻执行 event loop 机制(引擎启动)
- event loop 不断循环 callback queue,如有则移动到call stack 执行
- 然后继续轮询查找
4. DOM事件和 event loop
- 触发回调的时机不一样
- JS是单线程运行的,异步(ajax setTimeout等)使用回调,基于event loop;DOM事件也使用回调,基于event loop
- 所以它们两个在执行上有冲突,那就存在执行的先后次序
5. async / awiat
- 异步回调 会产生 callback hell
- promise then catch 是链式调用,但也是基于回调函数
- async/await是同步语法,彻底消灭回调函数(使用同步的语法方式来写异步函数)
6. async/await 和 promise 的关系
- async/await 是消灭异步回调的终极武器
- 但和promise并不互斥
- 反而,两者相辅相成
- 执行async 函数,返回的是promise对象
- await相当于promise的then,处理不了catch
- try...catch可捕获异常,代替了promise的catch
7. 异步的本质
- async/await 是消灭异步回调的终极武器——价值和意义
- JS还是单线程,还是得要异步,还是得基于event loop
- async/await 只是一个语法糖
8. for ... of
- for ... in / forEach for 是常规的同步遍历,如果用于异步循环会报错
- for ... of 常用于异步的循环
9. 宏任务 macroTask 和微任务 microTask
- 宏任务:setTimeout setInterval Ajax DOM事件;DOM 渲染后触发
- 微任务:promise async/await;DOM渲染前触发
- 因此,微任务执行时机比宏任务要早
10. event loop 和 DOM渲染
- JS是单线程,而且和DOM渲染共用一个线程
- 每次 call stack 清空(既每次轮询结束),即同步任务执行完
- 都是 DOM 重新渲染的机会,DOM 结构如有改变则重新渲染
- 然后再去触发下一次 event loop