promise面试题
1.
const promise = new Promise((resolve, reject) => {
console.log(1);
resolve();
console.log(2);
});
promise.then(() => {
console.log(3);
});
console.log(4);
//输出结果为:1,2,4,3。
解题思路:then方法是异步执行的。
2.
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
reject('error')
}, 1000)
})
promise.then((res)=>{
console.log(res)
},(err)=>{
console.log(err)
})
// 输出结果:success
解题思路:Promise状态一旦改变,无法在发生变更。
3.
Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log)
// 输出结果:1
解题思路:Promise的then方法的参数期望是函数,传入非函数则会发生值穿透。
4.
setTimeout(()=>{
console.log('setTimeout')
})
let p1 = new Promise((resolve)=>{
console.log('Promise1')
resolve('Promise2')
})
p1.then((res)=>{
console.log(res)
})
console.log(1)
//输出结果:
// Promise1
//1
//Promise2
//setTimeout
解题思路:这个牵扯到js的执行队列问题,整个script代码,放在了macrotask queue中,执行到setTimeout时会新建一个macrotask queue。但是,promise.then放到了另一个任务队列microtask queue中。script的执行引擎会取1个macrotask queue中的task,执行之。然后把所有microtask queue顺序执行完,再取setTimeout所在的macrotask queue按顺序开始执行。
5.
Promise.resolve(1)
.then((res) => {
console.log(res);
return 2;
})
.catch((err) => {
return 3;
})
.then((res) => {
console.log(res);
});
// 输出结果:1 2
解题思路:Promise首先resolve(1),接着就会执行then函数,因此会输出1,然后在函数中返回2。因为是resolve函数,因此后面的catch函数不会执行,而是直接执行第二个then函数,因此会输出2。
6.
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('开始');
resolve('success');
}, 5000);
});
const start = Date.now();
promise.then((res) => {
console.log(res, Date.now() - start);
});
promise.then((res) => {
console.log(res, Date.now() - start);
});
// 5s后输出结果:
//开始
//success 5002 或5001
//success 5002 或5001
解题思路:promise 的.then或者.catch可以被调用多次,但这里 Promise 构造函数只执行一次。或者说 promise 内部状态一经改变,并且有了一个值,then中的回调就会被调用。那么后续每次调用.then 或者.catch都会直接拿到该值。
7.
let p1 = new Promise((resolve,reject)=>{
let num = 6
if(num<5){
console.log('resolve1')
resolve(num)
}else{
console.log('reject1')
reject(num)
}
})
p1.then((res)=>{
console.log('resolve2')
console.log(res)
},(rej)=>{
console.log('reject2')
let p2 = new Promise((resolve,reject)=>{
if(rej*2>10){
console.log('resolve3')
resolve(rej*2)
}else{
console.log('reject3')
reject(rej*2)
}
})
return p2
}).then((res)=>{
console.log('resolve4')
console.log(res)
},(rej)=>{
console.log('reject4')
console.log(rej)
})
/*输出结果:
reject1
reject2
resolve3
resolve4
12
*/
解题思路:我们上面说了Promise的先进之处在于可以在then方法中继续写Promise对象并返回。
8.重头戏!!!!实现一个简单的Promise
function Promise(fn){
var status = 'pending'
function successNotify(){
status = 'fulfilled'//状态变为fulfilled
toDoThen.apply(undefined, arguments)//执行回调
}
function failNotify(){
status = 'rejected'//状态变为rejected
toDoThen.apply(undefined, arguments)//执行回调
}
function toDoThen(){
setTimeout(()=>{ // 保证回调是异步执行的
if(status === 'fulfilled'){
for(let i =0; i< successArray.length;i ++) {
successArray[i].apply(undefined, arguments)//执行then里面的回掉函数
}
}else if(status === 'rejected'){
for(let i =0; i< failArray.length;i ++) {
failArray[i].apply(undefined, arguments)//执行then里面的回掉函数
}
}
})
}
var successArray = []
var failArray = []
fn.call(undefined, successNotify, failNotify)
return {
then: function(successFn, failFn){
successArray.push(successFn)
failArray.push(failFn)
return undefined // 此处应该返回一个Promise
}
}
}
解题思路:Promise中的resolve和reject用于改变Promise的状态和传参,then中的参数必须是作为回调执行的函数。因此,当Promise改变状态之后会调用回调函数,根据状态的不同选择需要执行的回调函数。
9.
Promise.resolve()
.then(() => {
return new Error('error!!!')
})
.then((res) => {
console.log('then: ', res)
})
.catch((err) => {
console.log('catch: ', err)
})
/*结果
then: Error: error!!!
at Promise.resolve.then (<anonymous>:3:8)
at <anonymous>
*/
解释:.then 或者 .catch 中 return 一个 error 对象并不会抛出错误,所以不会被后续的 .catch 捕获,需要改成其中一种:
(1)return Promise.reject(new Error(‘error!!!’))
(2)throw new Error(‘error!!!’)
因为返回任意一个非 promise 的值都会被包裹成 promise 对象,即 return new Error(‘error!!!’) 等价于 return Promise.resolve(new Error(‘error!!!’))。
9.
const promise = Promise.resolve()
.then(() => {
return promise
})
promise.catch(console.error)
/*结果
TypeError: Chaining cycle detected for promise #<Promise>
at <anonymous>*/
解释:.then 或 .catch 返回的值不能是 promise 本身,否则会造成死循环。
10.
const promise1 = new Promise((resolve,reject)=>{
setTimeout(function(){
resolve('success');
},1000);
});
const promise2 = promise1.then(()=>{
throw new Error('error');
});
console.log("promise1",promise1);
console.log("promise2",promise2);
setTimeout(function(){
console.log("promise1",promise1);
console.log("promise2",promise2);
},2000);
/*结果
promise1 Promise {<pending>}
promise2 Promise {<pending>}
Uncaught (in promise) Error: error
promise1 Promise {<resolved>: "success"}
promise2 Promise {<rejected>: Error: error