Promise结合setTimeout
题目1
console.log('start')
setTimeout(() => {
console.log('time')
})
Promise.resolve().then(() => {
console.log('resolve')
})
console.log('end')`
输出:
start
end
resolve
time
分析:
- 执行同步代码:
- 打印start
- 设置计时器(setTimeout),回调函数进入宏任务队列
- 执行Promise.resolve.then(),回调函数是异步函数,进入微任务队列
- 打印end
- 检查微任务队列,将其中任务放入执行栈执行——
console.log('resolve');
,队列空 - 检查宏任务队列,将其中任务放入执行栈执行——
console.log('time')
同-->微-->宏
题目2
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);
输出:
1
2
4
timeStart
timeEnd
success
分析:
- 执行同步代码:
- 给promise赋值
- 打印1
- 设置计时器,回调函数是异步函数,进入宏任务队列
- 打印2
- 给promise的解决处理函数赋值(resolve指向一个函数),但因为promise尚未调用resolve,所以该回调函数尚未进入任务队列
- 打印4
- 检查微任务队列,为空
- 检查宏任务队列,依次执行
console.log("timerStart");
resolve("success");
console.log("timerEnd");
因为resolve是异步函数,会被放入微任务队列,当宏任务队列所有能执行的任务都取出后,开始新的循环
3. 执行栈为空,检查微任务队列,将微任务队列中的resolve放入执行栈执行,于是打印success
箭头函数能够保留它创建时的作用域,调用该作用域中的变量和函数,所以setTimeout改变执行流后,仍能调用resolve。
题目3
(1)
setTimeout(() => {
console.log('timer1');
setTimeout(() => {
console.log('timer3')
}, 0)
}, 0)
setTimeout(() => {
console.log('timer2')
}, 0)
console.log('start')
输出:
start
timer1
timer2
timer3
(2)
setTimeout(() => {
console.log('timer1');
Promise.resolve().then(() => {
console.log('promise')
})
}, 0)
setTimeout(() => {
console.log('timer2')
}, 0)
console.log('start')
输出:
start
timer1
promise
timer2
分析:
Promise.then是微任务,它会被加入到本轮中的微任务列表,而定时器timer3是宏任务,它会被加入到下一轮的宏任务中。
题目3
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');
输出:
start
promise1
timer1
promise2
timer2
分析:
- 执行同步代码:
- Promise.resolve.then()给resolve赋予一个箭头函数。该回调加入本轮微任务队列中,其中的定时器timer2将加入次轮宏任务队列
- 给timer1设置一个定时器,回调函数加入本轮宏任务队列,promise.then加入次轮微任务队列
- 打印start
- 检查微任务队列:
- 第一个Promise的解决处理函数被放入执行栈
- 打印promise1
- 为timer2添加定时器,回调函数加入本轮宏任务队列(已经是第二轮了)
- 执行栈为空
- 检查宏任务队列
- timer1定时器的回调函数转移到执行栈上
- 打印timer1
- 将第二个Promise的解决处理函数加入本轮微任务队列(已经是第二轮了)
- 执行栈为空
- 检查微任务队列
- 打印promise2
- 检查宏任务队列
- 打印timer2
题目4
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
//console.log("success 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)
输出:
promise1 Promise{<pending>}
promise2 Promise{<pending>}
//success setTimeout
Uncaught (in promise) Error: error!!!
promise1 Promise{<fulifilled> success}
promise2 Promise{<rejected> Error: error!!!}
分析:
- 执行同步代码
- 给promise1赋值
- 设置一个定时器,1秒后回调函数进入本轮宏任务队列
- 给promise2赋值,then的回调函数加入微任务队列
- 打印"promise1"和promise1的状态,目前promise1的状态依然是pending
- 打印"promise2"和promise2的状态,目前promise2的状态依然是pending
- 设置定时器,2秒后回调函数加入宏任务队列
- 检查微任务队列,空
- 检查宏任务队列,空
- 1秒,微任务队列依然为空
- 1秒,定时器触发,执行
resolve("success");
- promise2的处理函数被放入微任务队列
- 将微任务队列的回调函数放入执行栈处理——
throw new Error("error!!!")
,抛出错误 - 2秒,微任务队列为空
- 2秒,将宏任务调入执行栈执行
console.log('promise1', promise1)
console.log('promise2', promise2)
此时promise1-->fulfilled,promise2-->rejected
可以提前给期约的处理函数赋值,但只有当状态转变时,回调函数才会进入微任务队列
如果先转状态,那么给相应处理函数赋值时,回调函数就会进入微任务队列
题目5
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
Uncaught (in promise) Error: error!!!
timer2
promise1 Promise{<fulfilled> success}
promise2 Promise{<rejected> Error error!!!}
分析:
与上一题类似
感谢阅读。
百炼成钢!!!
参考:
【建议星星】要就来45道Promise面试题一次爽到底(1.1w字用心整理)
《JavaScript高级程序设计》(第四版)