event loop它的执行顺序:
- 一开始整个脚本作为一个宏任务执行
- 执行过程中同步代码直接执行,宏任务进入宏任务队列,微任务进入微任务队列
- 当前宏任务执行完出队,检查微任务列表,有则依次执行,直到全部执行完
- 执行浏览器UI线程的渲染工作
- 检查是否有Web Worker任务,有则执行
- 执行完本轮的宏任务,回到2,依此循环,直到宏任务和微任务队列都为空
微任务包括:MutationObserver、Promise.then()或reject()、Promise为基础开发的其它技术,比如fetch API、V8的垃圾回收过程、Node独有的process.nextTick。
宏任务包括:script、script 、setTimeout、setInterval 、setImmediate 、I/O 、UI rendering
# 1 Promise的几道基础题
# 1.1 题目一
⚡ 30 秒速记
new Promise(executor)会立即调用执行器- 顺序:
promise1→1与期约对象 - 没调用
resolve、reject,状态保持pending - 同步抛错也会拒绝,不能只查显式
reject - 控制台展开对象可能展示稍后的状态
这段代码先打印 promise1,再打印 1 和一个待定的期约对象。 Promise 构造器里的函数会同步执行,不会因为写在期约里就排到后面。执行器既没调用成功或失败回调,也没抛出异常,所以这个期约一直待定。真正延后执行的是通过 then 等方法注册的回调;创建期约本身仍是普通的同步调用。
const promise1 = new Promise((resolve, reject) => {
console.log('promise1')
})
console.log('1', promise1);
- 从上至下,先遇到new Promise,执行该构造函数中的代码promise1
- 然后执行同步代码1,此时promise1没有被resolve或者reject,因此状态还是pending
'promise1'
'1' Promise{<pending>}
💬 面试官追问
-
执行器里没有定时器,为什么期约还是待定?
待定只表示还没有得到成功或失败结果,与有没有异步操作无关。执行器执行结束不会自动完成期约。
-
执行器直接
return 123,状态会成功吗?不会,构造器忽略执行器的普通返回值。要通过
resolve(123)交付结果。 -
把第一行日志后面换成
throw new Error()呢?执行器中的同步异常会让期约拒绝。外层构造调用通常返回拒绝的期约,需要通过拒绝处理函数接住。
-
控制台展开后看到成功,能证明打印时已经成功吗?
不一定,开发工具可能延迟读取对象内容。分析顺序时根据代码状态变化判断,必要时记录独立的标量日志。
# 1.2 题目二
⚡ 30 秒速记
- 输出:
1 → 2 → 4 → 3 resolve('success')使期约成功,不终止执行器then回调走微任务,当前同步代码先完成return resolve(...)才能顺便退出当前函数- 区分“状态改变”和“回调执行”的时机
输出顺序是 1、2、4、3,因为完成期约不会打断正在执行的同步代码。 执行器先打印 1,调用 resolve 后继续打印 2;注册的 then 回调不会当场运行,所以外面的 4 先出现。等当前同步任务结束,微任务才打印 3。这里最容易混淆的是期约已经成功,但成功回调仍然要等待执行机会。