Promise 经典面试题
可复制题目到js在线运行工具看答案
题目一
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| Promise.resolve().then(() => { console.log(0); return Promise.resolve(4); }).then((res) => { console.log(res) }) Promise.resolve().then(() => { console.log(1); }).then(() => { console.log(2); }).then(() => { console.log(3); }).then(() => { console.log(5); }).then(() => { console.log(6); })
|
答案
解析
待解析
题目二
代码
1 2 3 4 5 6 7 8 9 10 11 12
| console.log('script start'); setTimeout(function() { console.log('setTimeout'); }, 0); new Promise(function(resolve) { console.log('promise1'); resolve(); console.log('promise2'); }).then(function() { console.log('promise then'); }); console.log('script end');
|
答案
1 2 3 4 5 6
| script start promise1 promise2 script end promise then setTimeout
|
解析
首先 JavaScript 引擎会执行一个宏任务,注意这个宏任务一般是指主干代码本身,也就是目前的同步代码;
执行过程中如果遇到微任务,就把它添加到微任务任务队列中;
宏任务执行完成后,立即执行当前微任务队列中的微任务,直到微任务队列被清空;
微任务执行完成后,开始执行下一个宏任务;
如此循环往复,直到宏任务和微任务被清空。
题目三
代码
1 2 3 4 5 6 7 8 9 10 11
| const promise = new Promise((resolve, reject) => { console.log(1); resolve(); console.log(2); })
promise.then(() => { console.log(3); })
console.log(4);
|
答案
解析
遇到 Promise 之后立即执行,输出 1,2
执行同步代码,输出 4
执行 promise.then() 中的代码,输出 3
题目四
代码
1 2 3 4 5 6 7 8 9 10 11
| 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); })
|
答案
解析
这里考察了 promise 的单向传递的特点,promise 有三种状态:
pending
resolved
rejected
这三种状态的转移只能是 pending -> resolved 或 pending -> rejected。不会出现 resolved -> rejected 或者 pending -> resolved -> rejected 等等,即状态只能从 pending 单向传递,且只能改变一次。
在 promise 中,resolve() 将 promise 的状态变为 resolved成功时调用,resolved 状态在先,先调用异步函数 promise.then((‘success1’) => { console.log(‘then:’, ‘success1’); })
promise 的状态一旦改变就不能修改了,因此 .catch() 和第二个 resolve(‘success2’) 不会执行。
题目五
代码
1 2 3 4
| Promise.resolve(1) .then(2) .then(Promise.resolve(3)) .then(console.log)
|
答案
解读
.then() 中的参数必须是函数,如果是非函数,则会发生值穿透,最终执行第三个 .then() 函数,参数为 1。
题目六
代码
1 2 3 4 5 6 7 8 9 10 11
| Promise.resolve(1) .then((res) => { console.log(res) return 2 }) .catch((err) => { return 3 }) .then((res) => { console.log(res) })
|
答案
解析
- promise.resolve() 返回一个新的 promise,执行第一个 .then(),参数为 1
- 打印 1,return 返回一个新的 promise,参数为 2
- 执行第二个 .then(),参数为 2,并打印出 2
题目七
代码
1 2 3 4 5 6 7 8 9 10
| Promise.resolve() .then(() => { return new Error('error!!!') }) .then((res) => { console.log('then: ', res) }) .catch((err) => { console.log('catch: ', err) })
|
解析
这里的陷阱在于只有抛出错误时才会执行 .catch(),题目中并不是抛出错误,所以执行 .then()。
改成如下方式会执行 .catch():
1 2 3
| return Promise.reject(new Error('error!!!'))
throw new Error('error!!!')
|
题目八
代码
1 2 3 4 5
| const promise = Promise.resolve() .then(() => { return promise }) promise.catch(console.error)
|
答案
程序报错
1
| TypeError: Chaining cycle detected for promise #<Promise>
|
解析
.then() 或 .catch() 返回的值不能是 promise 本身,否则会造成死循环。
题目九
代码
1 2 3 4 5 6 7 8
| setTimeout(() => { console.log(1) Promise.resolve(3).then(data => console.log(data)) }, 0)
setTimeout(() => { console.log(2) }, 0)
|
答案
解读
先执行整体代码,没有发现微任务;
再执行下一个宏任务—setTimeout回调函数,打印出1;
遇到微任务—Promise 回调函数;
立即执行微任务,打印出3;
微任务队列被清空,执行下一个宏任务—下一个setTimeout回调函数,打印出2。
题目十
代码
1 2 3 4 5 6 7 8 9 10 11 12
| var pro = new Promise((res, rej) => { res(1); }); pro.then(res => { console.log(res); }); setTimeout(() => { console.log(2); }) pro.then(res => { console.log(res); })
|
答案
解析
promise 对象赋值给了变量 pro,每个 .then() 都是独立的。
题目十一
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| 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');
|
答案
1 2 3 4 5 6 7 8
| script start async1 start async2 promise1 script end async1 end promise2 setTimeout
|
解析
注意以下几点:
- 定义 async1(),async2(),不会立即执行
- await async2(); 表示先执行 async2(),然后将 await 后面的代码当作 .then() 中的回调来处理
- 初始化 promise,promise 中的代码会立即执行
转自:https://leetcode-cn.com/circle/discuss/sQXY3u/