某大厂的一道普通的面试题(稍作修改,增加了难度),可以先看看题目,然后再对照下答案。
const p = () => new Promise((resolve, reject) => {
console.log(1)
const q = () => new Promise((resolve, reject) => {
console.log(3)
resolve(4)
})
const r = () => new Promise((resolve, reject) => {
console.log(7)
resolve(8)
})
setTimeout(() => {
console.log(10)
}, 0);
resolve(2)
q().then(res => {
console.log(res)
setTimeout(() => {
console.log(6)
}, 0);
})
r().then(res => {
console.log(res)
setTimeout(() => {
console.log(9)
}, 0);
})
})
p().then(res => {
console.log(res)
})
console.log(5)
/**
*
* Promise是一种异步编程的解决方案,主要解决的是回调函数多层嵌套造成的回调地狱的问题
* Promise对象的内部有三种状态,pending fullfilled rejected, pendeing是最初始的状态,成功是resolve(res),失败是reject(res),成功或者失败的结果均作为参数被抛出,并分别在then和catch中作为参数暴露
* Promise 一旦被声明就会立即执行,此时内部的代码会按照顺序执行,但是resolve(res)的代码会是异步,所以当Promise()中的同步代码会先执行,resolve()的代码会后执行,resolve()之后的也先执行,Promise中的所有的同步和异步代码执行完毕之后resolve()才执行
* 1 3 7 5 4 8 2 10 6 9
* 下面这段代码的执行顺序如上所示
* 我们应该分三个阶段去看这段代码的执行
* 阶段1: 同步代码先执行
* 因为同步代码最先执行,又因为Promise一旦被调用就会立即执行所以会打印 - 1
* resolve(2) 作为异步仍在等待同步代码执行完毕且 p 内部的全部代码执行完毕之后才会被执行
* 然后声明了一个q, r 的 Promise 然后调用 q ,同步代码立即执行 打印 - 3
* resolve(4) 作为异步仍在等待同步代码执行完毕且 q 内部的代码全部执行完成之后才会被执行
* 同理,打印 r 中的同步代码 - 7 ,resolve(8)作为异步等待
* 到这里 p 内部的同步代码执行完毕了,此时跳出 p 执行外部的同步代码,打印 - 5
*
* 此时执行的代码的顺序为 1 3 7 5
*
* 阶段2:Promise()中异步的resolve()执行
* 当同步执行之后就是resolve()异步的代码,p()先执行,但是 p()自己的resolve() 必须等到其内部全部的异步resove()执行完毕之后才能够执行
* 所以此时应该是先执行的是 q().then() 打印 - 4
* 然后打印的是 r().then() 打印 - 8
* 然后 p() 内部的 resolve() 异步全部执行完毕,最后就要执行 p().then() 打印2
*
* 此时执行的代码的顺序为 4 8 2
*
* 阶段3:setTimeout 异步函数的执行
* 由于 Promise 是 JS 引擎的内部任务,而setTimeout 是浏览器外部的API 所以 Promise 的优先级高于 setTimeout ,也就是因此,只有所有的 Promise()内的resolve()执行完成之后才会执行 setTimeout 函数
* 而 setTimeout 函数执行的顺序就看它被调用的先后顺序了
* 从上到下依次调用 打印 - 10 6 9
*
* 到此三个阶段全部结束 程序执行完毕
*/