大家好,我是 CoderBin
前言
在面试中,最常见的输出题应该就是与 Promise 相关的事件循环了吧,在上一文总结了事件循环后这次准备给大伙们安排几十道练习题,快快收藏起来~ 相信看完这些题,在面试当中肯定能妥妥的拿捏了,再也不怕类似的题目啦👌
下面代码皆在 node 环境下运行。如果文中有不对、疑惑的地方,欢迎在评论区留言指正🌻
想复习事件循环的可前往:面试官:说说你对事件循环的理解
高频面试总结
【1】75道关于CSS的高频面试题总结,请注意查收!🔥
【2】关于Vue的一些高频面试题总结
面试官系列文章
【1】面试官:你说说 js 中实现继承有哪几种方法?
【2】面试官:说说你对事件循环的理解
1. Promise 第一题
const promise1 = new Promise((resolve, reject) => {
console.log('promise1')
})
console.log('1', promise1)
复制代码
解析:
答案:
promise1
1 Promise { <pending> }
复制代码
2. Promise 第二题
const promise = new Promise((resolve, reject) => {
console.log(1)
resolve('success')
console.log(2)
})
promise.then(() => {
console.log(3)
})
console.log(4)
复制代码
解析:
从上至下,先遇到new Promise
,执行其中的同步代码 1
再遇到resolve('success')
, 将 promise 的状态改为了 resolved 并且将值保存下来
继续执行同步代码 2
跳出 promise,往下执行,碰到promise.then
这个微任务,将其加入微任务队列
执行同步代码 4
本轮宏任务全部执行完毕,检查微任务队列,发现promise.then
这个微任务且状态为 resolved,执行它。
答案:1、2、4、3
3. Promise 第三题
const promise = new Promise((resolve, reject) => {
console.log(1)
console.log(2)
})
promise.then(() => {
console.log(3)
})
console.log(4)
复制代码
解析:
答案:1、2、4
4. Promise 第四题
const promise1 = new Promise((resolve, reject) => {
console.log('promise1')
resolve('resolve1')
})
const promise2 = promise1.then(res => {
console.log(res)
})
console.log('1', promise1)
console.log('2', promise2)
复制代码
解析:
从上至下,先遇到new Promise
,执行该构造函数中的代码promise1
碰到resolve
函数, 将promise1
的状态改变为resolved
, 并将结果保存下来
碰到promise1.then
这个微任务,将它放入微任务队列
promise2
是一个新的状态为pending
的Promise
执行同步代码 1, 同时打印出 promise1 的状态是 resolved
执行同步代码 2,同时打印出 promise2 的状态是 pending
宏任务执行完毕,查找微任务队列,发现promise1.then
这个微任务且状态为resolved
,执行它。
答案:
promise1
1 Promise { 'resolve1' }
2 Promise { <pending> }
resolve
复制代码
5. Promise 第五题
const fn = () => (new Promise((resolve, reject) => {
console.log(1);
resolve('success')
}))
fn().then(res => {
console.log(res)
})
console.log('start')
复制代码
解析:fn
函数直接返回了一个new Promise
的,而且fn
函数的调用是在start
之前,所以它里面的内容应该会先执行。
答案:1、'start'、'success'
6. Promise 第六题
const fn = () => {
return new Promise((resolve, reject) => {
console.log(1)
resolve('success')
})
}
console.log('start')
fn().then(res => {
console.log(res)
})
复制代码
解析:start 就在 1 之前打印出来了,因为 fn 函数是之后执行的。
注意:不要看到new Promise()
,就以为执行它的第一个参数函数,我们还需要注意它是不是被包裹在函数当中,如果是的话,只有在函数调用的时候才会执行。
答案:"start"、1、"success"
7. Promise 第七题
console.log('start')
setTimeout(() => {
console.log('time')
})
Promise.resolve().then(() => {
console.log('resolve')
})
console.log('end')
复制代码
解析:
刚开始整个脚本作为一个宏任务来执行,对于同步代码直接压入执行栈进行执行,因此先打印出start
和end
。
setTimout
作为一个宏任务被放入宏任务队列(下一个)
Promise.then
作为一个微任务被放入微任务队列
本次宏任务执行完,检查微任务,发现Promise.then
,执行它
接下来进入下一个宏任务,发现setTimeout
,执行。
答案:'start'、'end'、'resolve'、'time'
8. Promise 第八题
const promise = new Promise((resolve, reject) => {
console.log(1)
setTimeout(() => {
console.log('timerStart')
resolve('success')
console.log('timerEnd')
}, 0)
console.log(2)
})
promise.then(res => {
console.log(res)
})
console.log(4)
复制代码
解析:
从上至下,先遇到new Promise
,执行该构造函数中的代码1
然后碰到了定时器,将这个定时器中的函数放到下一个宏任务的延迟队列中等待执行
执行同步代码2
跳出promise
函数,遇到promise.then
,但其状态还是为pending
,这里理解为先不执行
执行同步代码4
一轮循环过后,进入第二次宏任务,发现延迟队列中有setTimeout
定时器,执行它
首先执行timerStart
,然后遇到了resolve
,将promise
的状态改为resolved
且保存结果并将之前的promise.then
推入微任务队列
继续执行同步代码timerEnd
宏任务全部执行完毕,查找微任务队列,发现promise.then
这个微任务,执行它。
答案:1、2、4、"timerStart"、"timerEnd"、"success"
9. Promise 第九题
下面两段代码会输出什么
setTimeout(() => {
console.log('timer1')
setTimeout(() => {
console.log('timer3')
}, 0)
}, 0)
setTimeout(() => {
console.log('timer2')
}, 0)
console.log('start')
复制代码
答案:'start'、'timer1'、'timer2'、'timer3'
setTimeout(() => {
console.log('timer1')
Promise.resolve().then(() => {
console.log('promise')
})
}, 0)
setTimeout(() => {
console.log('timer2')
}, 0)
console.log('start')
复制代码
答案:'start'、'timer1'、'promise'、'timer2'
解析:这两个例子,看着好像只是把第一个定时器中的内容换了一下而已。
一个是为定时器 timer3,一个是为 Promise.then
但是如果是定时器 timer3 的话,它会在 timer2 后执行,而 Promise.then 却是在 timer2 之前执行。
你可以这样理解,Promise.then 是微任务,它会被加入到本轮中的微任务列表,而定时器 timer3 是宏任务,它会被加入到下一轮的宏任务中。
10. Promise 第十题
Promise.resolve().then(() => {
console.log('promise1')
const timer2 = setTimeout(() => {
console.log('timer2')
}, 0)
})
const timer1 = setTimeout(() => {
console.log('timer1')
Promise.resolve().then(() => {
console.log('promise2')
})
}, 0)
console.log('start')
复制代码
解析:
刚开始整个脚本作为第一次宏任务来执行,我们将它标记为宏 1,从上至下执行
遇到Promise.resolve().then
这个微任务,将then
中的内容加入第一次的微任务队列标记为微 1
遇到定时器timer1
,将它加入下一次宏任务的延迟列表,标记为宏 2,等待执行(先不管里面是什么内容)
执行宏 1 中的同步代码start
第一次宏任务(宏 1)执行完毕,检查第一次的微任务队列(微 1),发现有一个promise.then
这个微任务需要执行
执行打印出微 1 中同步代码promise1
,然后发现定时器 timer2,将它加入宏 2 的后面,标记为宏 3
第一次微任务队列(微 1)执行完毕,执行第二次宏任务(宏 2),首先执行同步代码timer1
然后遇到了promise2
这个微任务,将它加入此次循环的微任务队列,标记为微 2
宏 2 中没有同步代码可执行了,查找本次循环的微任务队列(微 2),发现了promise2
,执行它
第二轮执行完毕,执行宏 3,打印出timer2
答案:'start'、'promise1'、'timer1'、'promise2'、'timer2'
11. Promise 第十一题
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 1000)
})
const promise2 = promise1.then(() => {
throw new Error('error!!!')
})
console.log('promise1', promise1)
console.log('promise2', promise2)
setTimeout(() => {
console.log('promise1', promise1)
console.log('promise2', promise2)
}, 2000)
复制代码
解析:
从上至下,先执行第一个new Promise
中的函数,碰到setTimeout
将它加入下一个宏任务列表
跳出new Promise
,碰到promise1.then
这个微任务,但其状态还是为pending
,这里理解为先不执行
promise2
是一个新的状态为pending
的Promise
执行同步代码console.log('promise1')
,且打印出的 promise1 的状态为 pending
执行同步代码console.log('promise2')
,且打印出的 promise2 的状态为 pending
碰到第二个定时器,将其放入下一个宏任务列表
第一轮宏任务执行结束,并且没有微任务需要执行,因此执行第二轮宏任务
先执行第一个定时器里的内容,将promise1
的状态改为 resolved 且保存结果并将之前的promise1.then
推入微任务队列
该定时器中没有其它的同步代码可执行,因此执行本轮的微任务队列,也就是promise1.then
,它抛出了一个错误,且将promise2
的状态设置为了 rejected
第一个定时器执行完毕,开始执行第二个定时器中的内容
打印出'promise1',且此时 promise1 的状态为 resolved
打印出'promise2',且此时 promise2 的状态为 rejected
答案:
'promise1' Promise{<pending>}
'promise2' Promise{<pending>}
UnhandledPromiseRejectionWarning: Error: error!!!
'promise1' Promise{<resolved>: "success"}
'promise2' Promise{<rejected>: Error: error!!!}
复制代码
12. Promise 第十二题
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
console.log('timer1')
}, 1000)
console.log('promise1里的内容')
})
const promise2 = promise1.then(() => {
throw new Error('error!!!')
})
console.log('promise1', promise1)
console.log('promise2', promise2)
setTimeout(() => {
console.log('timer2')
console.log('promise1', promise1)
console.log('promise2', promise2)
}, 2000)
复制代码
答案:和上一题类似
'promise1里的内容'
'promise1' Promise{<pending>}
'promise2' Promise{<pending>}
'timer1'
UnhandledPromiseRejectionWarning: Error: error!!!
'timer2'
'promise1' Promise{<resolved>: "success"}
'promise2' Promise{<rejected>: Error: error!!!}
复制代码
13. Promise 第十三题
const promise = new Promise((resolve, reject) => {
resolve('success1')
reject('error')
resolve('success2')
})
promise.then(res => {
console.log('then: ', res)
}).catch(err => {
console.log('catch: ', err)
})
复制代码
解析:构造函数中的 resolve 或 reject 只有第一次执行有效,多次调用没有任何作用 ,Promise 的状态一经改变就不能再改变。
答案:"then: success1"
14. Promise 第十四题
const promise = new Promise((resolve, reject) => {
reject('error')
resolve('success2')
})
promise.then(res => {
console.log('then1: ', res)
}).then(res => {
console.log('then2: ', res)
}).catch(err => {
console.log('catch: ', err)
}).then(res => {
console.log('then3: ', res)
})
复制代码
解析:catch
不管被连接到哪里,都能捕获上层未捕捉过的错误。
至于then3
也会被执行,那是因为catch()
也会返回一个 Promise,且由于这个 Promise 没有返回值,所以打印出来的是undefined
。
答案:
catch: error
then3: undefined
复制代码
15. Promise 第十五题
Promise.resolve(1)
.then(res => {
console.log(res)
return 2
})
.catch(err => {
return 3
})
.then(res => {
console.log(res)
})
复制代码
解析:Promise 可以链式调用,不过 promise 每次调用 .then
或者 .catch
都会返回一个新的 promise,从而实现了链式调用, 它并不像一般我们任务的链式调用一样 return this。
上面的输出结果之所以依次打印出 1 和 2,那是因为resolve(1)
之后走的是第一个 then 方法,并没有走 catch 里,所以第二个 then 中的 res 得到的实际上是第一个 then 的返回值。且 return 2 会被包装成resolve(2)
。
答案:1、2
16. Promise 第十六题
Promise.reject(1)
.then(res => {
console.log(res)
return 2
})
.catch(err => {
console.log(err)
return 3
})
.then(res => {
console.log(res)
})
复制代码
解析:因为 reject(1),此时走的是 catch,且第二个 then 中的 res 得到的就是 catch 中的返回值。
答案:1、3
17. Promise 第十七题
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('timer')
resolve('success')
}, 1000)
})
const start = Date.now()
promise.then(res => {
console.log(res, Date.now() - start)
})
promise.then(res => {
console.log(res, Date.now() - start)
})
复制代码
解析:如果执行足够快的话,也可能两个都是 1001。
Promise 的 .then
或者 .catch
可以被调用多次,但这里 Promise
构造函数只执行一次。或者说 promise 内部状态一经改变,并且有了一个值,那么后续每次调用 .then
或者 .catch
都会直接拿到该值。
答案:
timer
success 1024
success 1026
复制代码
18. Promise 第十八题
Promise.resolve()
.then(() => {
return new Error('error!!!')
})
.then(res => {
console.log('then: ', res)
})
.catch(err => {
console.log('catch: ', err)
})
复制代码
解析:返回任意一个非 promise 的值都会被包裹成 promise 对象,因此这里的return new Error('error!!!')
也被包裹成了return Promise.resolve(new Error('error!!!'))
。
答案:"then: " "Error: error!!!"
19. Promise 第十九题
const promise = Promise.resolve().then(() => {
return promise
})
promise.catch(console.err)
复制代码
解析:.then
或 .catch
返回的值不能是 promise 本身,否则会造成死循环,因此结果会报错。
答案:
UnhandledPromiseRejectionWarning: TypeError: Chaining cycle detected for promise #<Promise>
复制代码
20. Promise 第二十题
Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log)
复制代码
解析:.then
或者 .catch
的参数期望是函数,传入非函数则会发生值透传。
第一个 then 和第二个 then 中传入的都不是函数,一个是数字类型,一个是对象类型,因此发生了透传,将resolve(1)
的值直接传到最后一个 then 里。
答案:1
21. Promise 第二十一题
Promise.reject('err!!!')
.then(
res => {
console.log('success', res)
},
err => {
console.log('error', err)
}
)
.catch(err => {
console.log('catch', err)
})
复制代码
解析:.then
函数中的两个参数。
第一个参数是用来处理 Promise 成功的函数,第二个则是处理失败的函数。
也就是说 Promise.resolve('1')的值会进入成功的函数,而Promise.reject('err!!!')
的值会进入失败的函数。
答案:'error' 'error!!!'
22. Promise 第二十二题
Promise.resolve()
.then(
function success(res) {
throw new Error('error!!!')
},
function fail1(err) {
console.log('fail1', err)
}
)
.catch(function fail2(err) {
console.log('fail2', err)
})
复制代码
解析:由于 Promise 调用的是resolve()
,因此.then()
执行的应该是success()
函数,可是 success()函数抛出的是一个错误,它会被后面的catch()
给捕获到,而不是被 fail1 函数捕获。
答案:
fail2 Error: error!!!
at success
复制代码
23. Promise 第二十三题
Promise.resolve('1')
.then(res => {
console.log(res)
})
.finally(() => {
console.log('finally')
})
Promise.resolve('2')
.finally(() => {
console.log('finally2')
return '我是finally2返回的值'
})
.then(res => {
console.log('finally2后面的then函数', res)
})
复制代码
解析:.finally()
,这个功能一般不太用在面试中,不过如果碰到了你也应该知道该如何处理。
其实只要记住它三个很重要的知识点就可以了:
.finally()
方法不管 Promise 对象最后的状态如何都会执行
.finally()
方法的回调函数不接受任何的参数,也就是说你在.finally()函数中是没法知道 Promise 最终的状态是 resolved 还是 rejected 的
它最终返回的默认会是一个上一次的 Promise 对象值,不过如果抛出的是一个异常则返回异常的 Promise 对象。
上面的代码中,这两个 Promise 的.finally 都会执行,且就算 finally2 返回了新的值,它后面的 then()函数接收到的结果却还是'2'。
答案:
1
finally2
finally
finally2后面的then函数 2
复制代码
24. Promise 第二十四题
function promise1() {
let p = new Promise(resolve => {
console.log('promise1')
resolve('1')
})
return p
}
function promise2() {
return new Promise((resolve, reject) => {
reject('error')
})
}
promise1()
.then(res => console.log(res))
.catch(err => console.log(err))
.finally(() => console.log('finally1'))
promise2()
.then(res => console.log(res))
.catch(err => console.log(err))
.finally(() => console.log('finally2'))
复制代码
解析:
首先定义了两个函数promise1
和promise2
,先不管接着往下看。
promise1
函数先被调用了,然后执行里面new Promise
的同步代码打印出promise1
之后遇到了resolve(1)
,将p
的状态改为了resolved
并将结果保存下来。
此时promise1
内的函数内容已经执行完了,跳出该函数
碰到了promise1().then()
,由于promise1
的状态已经发生了改变且为resolved
。因此将·promise1().then()·这条微任务加入本轮的微任务列表(这是第一个微任务)
这时候要注意了,代码并不会接着往链式调用的下面走,也就是不会先将.finally
加入微任务列表,那是因为.then
本身就是一个微任务,它链式后面的内容必须得等当前这个微任务执行完才会执行,因此这里我们先不管.finally()
再往下走碰到了promise2()
函数,其中返回的new Promise
中并没有同步代码需要执行,所以执行reject('error')
的时候将promise2
函数中的Promise
的状态变为了rejected
跳出promise2
函数,遇到了promise2().catch()
,将其加入当前的微任务队列(这是第二个微任务),且链式调用后面的内容得等该任务执行完后才执行,和.then()
一样。
本轮的宏任务全部执行完了,来看看微任务列表,存在promise1().then()
,执行它,打印出 1,然后遇到了.finally()
这个微任务将它加入微任务列表(这是第三个微任务)等待执行
再执行promise2().catch()
打印出error
,执行完后将finally2
加入微任务加入微任务列表(这是第四个微任务)
本轮又全部执行完了,但是微任务列表还有两个新的微任务没有执行完,因此依次执行finally1
和finally2
。
答案:
promise1
1
error
finally1
finally2
复制代码
25. Promise 第二十五题
function runAsync(x) {
const p = new Promise(r => {
setTimeout(() => {
r(x, console.log(x))
}, 1000)
})
return p
}
Promise.all([runAsync(1), runAsync(2), runAsync(3)]).then(res => {
console.log(res)
})
复制代码
解析:.all()
的作用是接收一组异步任务,然后并行执行异步任务,并且在所有异步操作执行完后才执行回调。
答案:1、2、3、[1, 2, 3]
26. Promise 第二十六题
function runAsync(x) {
const p = new Promise( r => {
setTimeout(() => {
r(x, console.log(x))
}, 1000)
})
return p
}
function runReject(x) {
const p = new Promise((res, rej) =>
setTimeout(() => {
rej(`Error: ${x}`, console.log(x))
}, 1000 * x)
)
return p
}
Promise.all([runAsync(1), runReject(4), runAsync(3), runReject(2)])
.then(res => console.log(res))
.catch(err => console.log(err))
复制代码
解析:.catch
是会捕获最先的那个异常,在这道题目中最先的异常就是runReject(2)
的结果。
答案:
// 1s后输出
1
3
// 2s后输出
2
Error: 2
// 4s后输出
4
复制代码
27. Promise 第二十七题
function runAsync(x) {
const p = new Promise(r => {
setTimeout(() => {
r(x, console.log(x))
}, 1000)
})
return p
}
function runReject(x) {
const p = new Promise((res, rej) =>
setTimeout(() => {
rej(`Error: ${x}`, console.log(x))
}, 1000 * x)
)
return p
}
Promise.race([runReject(0), runAsync(1), runAsync(2), runAsync(3)])
.then(res => console.log('result: ', res))
.catch(err => console.log(err))
复制代码
解析:.race()
的作用也是接收一组异步任务,然后并行执行异步任务,只保留取第一个执行完成的异步操作的结果,其他的方法仍在执行,不过执行结果会被抛弃。
答案:
28. Promise 第二十八题
async function async1() {
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2() {
console.log('async2')
}
async1()
console.log('start')
复制代码
解析:
首先一进来是创建了两个函数的,我们先不看函数的创建位置,而是看它的调用位置
发现async1
函数被调用了,然后去看看调用的内容
执行函数中的同步代码async1 start
,之后碰到了 await,它会阻塞 async1 后面代码的执行,因此会先去执行async2
中的同步代码 async2,然后跳出async1
跳出 async1 函数后,执行同步代码 start
在一轮宏任务全部执行完之后,再来执行刚刚 await 后面的内容async1 end
。
在这里,你可以理解为「紧跟着 await 后面的语句相当于放到了new Promise
中,下一行及之后的语句相当于放在Promise.then
中」。
答案:
async1 start
async2
start
async1 end
复制代码
29. Promise 第二十九题
async function async1() {
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2() {
setTimeout(() => {
console.log('timer')
}, 0)
console.log('async2')
}
async1()
console.log('start')
复制代码
解析:定时器始终还是最后执行的,它被放到下一条宏任务的延迟队列中。
答案:
async1 start
async2
start
async1 end
timer
复制代码
30. Promise 第三十题
async function async1() {
console.log('async1 start')
await async2()
console.log('async1 end')
setTimeout(() => {
console.log('timer1')
}, 0)
}
async function async2() {
setTimeout(() => {
console.log('timer2')
}, 0)
console.log('async2')
}
async1()
setTimeout(() => {
console.log('timer3')
}, 0)
console.log('start')
复制代码
解析:不管定时器谁先执行,你只需要关注谁先被调用的以及延迟时间是多少,这道题中延迟时间都是 0,所以只要关注谁先被调用的。
答案:
async1 start
async2
start
async1 end
timer2
timer3
timer1
复制代码
31. Promise 第三十一题
async function fn () {
// return await 1234
// 等同于
return 123
}
fn().then(res => console.log(res))
复制代码
解析:正常情况下,async 中的 await 命令是一个 Promise 对象,返回该对象的结果。
但如果不是 Promise 对象的话,就会直接返回对应的值,相当于Promise.resolve()
答案:123
32. Promise 第三十二题
async function async1() {
console.log('async1 start')
await new Promise(resolve => {
console.log('promise1')
})
console.log('async1 success')
return 'async1 end'
}
console.log('srcipt start')
async1().then(res => console.log(res))
console.log('srcipt end')
复制代码
解析:在 async1 中 await 后面的 Promise 是没有返回值的,也就是它的状态始终是 pending 状态,因此相当于一直在 await,await,await 却始终没有响应...
所以在 await 之后的内容是不会执行的,也包括 async1 后面的 .then。
答案:
srcipt start
async1 start
promise1
srcipt end
复制代码
33. Promise 第三十三题
async function async1() {
console.log('async1 start')
await new Promise(resolve => {
console.log('promise1')
resolve('promise resolve')
})
console.log('async1 success')
return 'async1 end'
}
console.log('srcipt start')
async1().then(res => {
console.log(res)
})
new Promise(resolve => {
console.log('promise2')
setTimeout(() => {
console.log('timer')
})
})
复制代码
解析:这道题也不难,不过有一点需要注意的,在 async1 中的new Promise
resovle 的值,和async1().then()
里的值是没有关系的,很多小伙伴可能看到resovle('promise resolve')
就会误以为是async1().then()
中的返回值。
答案:
async1 start
promise1
promise2
async1 success
async1 end
timer
复制代码
34. Promise 第三十四题
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
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
复制代码
35. Promise 第三十五题
async function testSometing() {
console.log('执行testSometing')
return 'testSometing'
}
async function testAsync() {
console.log('执行testAsync')
return Promise.resolve('hello async')
}
async function test() {
console.log('test start...')
const v1 = await testSometing()
console.log(v1)
const v2 = await testAsync()
console.log(v2)
console.log(v1, v2)
}
test()
var promise = new Promise(resolve => {
console.log('promise start...')
resolve('promise')
})
promise.then(val => console.log(val))
console.log('test end...')
复制代码
解析:这里直给出答案
答案:
test start...
执行testSometing
promise start...
test end...
testSometing
执行testAsync
promise
hello async
testSometing hello async
复制代码
36. Promise 第三十六题
async function async1() {
await async2()
console.log('async1')
return 'async1 success'
}
async function async2() {
return new Promise((resolve, reject) => {
console.log('async2')
reject('error')
})
}
async1().then(res => console.log(res))
复制代码
解析:直接给出答案答案:
async2
(node:10244) UnhandledPromiseRejectionWarning: error
复制代码
37. Promise 第三十七题
async function async1() {
try {
await Promise.reject('error!!!')
} catch (e) {
console.log(e)
}
console.log('async1')
return Promise.resolve('async1 success')
}
async1().then(res => console.log(res))
console.log('script start')
复制代码
解析:直接给出答案
答案:
script start
error!!!
async1
async1 success
复制代码
38. Promise 第三十八题
const first = () =>
new Promise((resolve, reject) => {
console.log(3)
let p = new Promise((resolve, reject) => {
console.log(7)
setTimeout(() => {
console.log(5)
resolve(6)
console.log(p)
}, 0)
resolve(1)
})
resolve(2)
p.then(arg => {
console.log(arg)
})
})
first().then(arg => {
console.log(arg)
})
console.log(4)
复制代码
解析:
第一段代码定义的是一个函数,所以我们得看看它是在哪执行的,发现它在 4 之前,所以可以来看看 first 函数里面的内容了。
函数 first 返回的是一个new Promise()
,因此先执行里面的同步代码 3
接着又遇到了一个new Promise()
,直接执行里面的同步代码 7
执行完 7 之后,在 p 中,遇到了一个定时器,先将它放到下一个宏任务队列里不管它,接着向下走
碰到了resolve(1)
,这里就把 p 的状态改为了 resolved,且返回值为 1,不过这里也先不执行
跳出 p,碰到了resolve(2)
,这里的resolve(2)
,表示的是把 first 函数返回的那个 Promise 的状态改了,也先不管它。
然后碰到了p.then
,将它加入本次循环的微任务列表,等待执行
跳出 first 函数,遇到了first().then()
,将它加入本次循环的微任务列表(p.then 的后面执行)
然后执行同步代码 4
本轮的同步代码全部执行完毕,查找微任务列表,发现p.then
和first().then()
,依次执行,打印出 1 和 2
本轮任务执行完毕了,发现还有一个定时器没有跑完,接着执行这个定时器里的内容,执行同步代码 5
然后又遇到了一个 resolve(6),它是放在 p 里的,但是 p 的状态在之前已经发生过改变了,因此这里就不会再改变,也就是说 resolve(6)相当于没任何用处,因此打印出来的 p 为Promise{<resolved>: 1}
。
答案:
39. Promise 第三十九题
const async1 = async () => {
console.log('async1')
setTimeout(() => {
console.log('timer1')
}, 2000)
await new Promise(resolve => {
console.log('promise1')
})
console.log('async1 end')
return 'async1 success'
}
console.log('script start')
async1().then(res => console.log(res))
console.log('script end')
Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.catch(4)
.then(res => console.log(res))
setTimeout(() => {
console.log('timer2')
}, 1000)
复制代码
解析:需要注意的点:
答案:
script start
async1
promise1
script end
1
timer2
timer1
复制代码
40. Promise 第四十题
const p1 = new Promise(resolve => {
setTimeout(() => {
resolve('resolve3')
console.log('timer1')
}, 0)
resolve('resovle1')
resolve('resolve2')
})
.then(res => {
console.log(res)
setTimeout(() => {
console.log(p1)
}, 1000)
})
.finally(res => {
console.log('finally', res)
})
复制代码
解析:
Promise 的状态一旦改变就无法改变
finally 不管 Promise 的状态是resolved
还是rejected
都会执行,且它的回调函数是接收不到 Promise 的结果的,所以 finally()中的 res 是一个迷惑项。
最后一个定时器打印出的 p1 其实是.finally
的返回值,我们知道.finally
的返回值如果在没有抛出错误的情况下默认会是上一个 Promise 的返回值,而这道题中.finally
上一个 Promise 是.then()
,但是这个.then()
并没有返回值,所以 p1 打印出来的 Promise 的值会是undefined
,如果你在定时器的下面加上一个return 1
,则值就会变成 1。
答案:
resovle1
finally undefined
timer1
Promise { undefined }
复制代码
往期推荐 💐 🌸 🌹 🌻 🌺 🍁
高阅读好文:
【1】关于Vue的一些高频面试题总结
【2】75道关于CSS的高频面试题总结,请注意查收!🔥
【3】Vue内置指令大全
【4】面试官:你说说 js 中实现继承有哪几种方法?
【5】一篇文章带你搞懂 this 的四个绑定规则 ✍
----- 🌻 查看全部 🍁 -----
每文一句:一个能思考的人,才真是一个力量无边的人。——巴尔扎克
本次的分享就到这里,如果本章内容对你有所帮助的话欢迎点赞+收藏。文章有不对的地方欢迎指出,有任何疑问都可以在评论区留言。希望大家都能够有所收获,大家一起探讨、进步!
评论