2024年中复习梳理一:Promise

100 阅读8分钟

复习梳理一:Promise

定义

promise是异步编程的一种解决方案。是一个微任务。

2个特点

(1)对象的状态不受外界影响。(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。

3个状态

pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态

优点

有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数

缺点

Promise也有一些缺点。首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

Promise考点

  • Promise 新建后就会立即执行.
  • 调用resolvereject并不会终结 Promise 的参数函数的执行.
  • Promise 状态已经变成resolved,再抛出错误是无效的
  • finally方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果
  • promise.all 场景。如果作为参数的 Promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()catch方法
  • 立即resolve()的 Promise 对象,是在本轮“事件循环”(event loop)的结束时执行,而不是在下一轮“事件循环”的开始时
  • .then和.catch都会返回一个新的Promise

promise的API

then()

Promise.prototype.then()

catch()

Promise.prototype.catch()

finally()

Promise.prototype.finally()

all()

Promise.all()

race()

Promise.race()

allSettled()

Promise.allSettled()

any()

Promise.any()

resolve()

Promise.resolve()

reject()

Promise.reject()

try()

Promise.try()

刷题

题1

考点:Promise 新建后就会立即执行

let promise = new Promise(function(resolve, reject) {
  console.log('Promise');
  resolve();
});

promise.then(function() {
  console.log('resolved.');
});

console.log('Hi!');

// Promise
// Hi!
// resolved.

题2

考点:调用resolvereject并不会终结 Promise 的参数函数的执行

new Promise((resolve, reject) => {
  resolve(1);
  console.log(2);
}).then(r => {
  console.log(r);
});
// 2
// 1

补充:一般来说,调用resolvereject以后,Promise 的使命就完成了,后继操作应该放到then方法里面,而不应该直接写在resolvereject的后面。所以,最好在它们前面加上return语句,这样就不会有意外。

const p = new Promise((resolve, reject) => {
  return resolve(1);
  // 后面的语句不会执行
  console.log(2);
})

console.log(3);

// 3
// 1

题3

考点:Promise 状态已经变成resolved,再抛出错误是无效的

const promise = new Promise(function(resolve, reject) {
  resolve('ok');
  throw new Error('test'); // 无效
});
promise
  .then(function(value) { console.log(value) })
  .catch(function(error) { console.log(error) });

// ok

题4

考点:如果作为参数的 Promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()catch方法

const p1 = new Promise((resolve, reject) => {
  resolve('hello');
})
.then(result => result)
.catch(e => e);

const p2 = new Promise((resolve, reject) => {
  throw new Error('报错了');
})
.then(result => result)
.catch(e => e); // 自己定义了catch

Promise.all([p1, p2])
.then(result => console.log(result)) // 走这里
.catch(e => console.log(e));
// ['hello', 'Error 报错了']

如果p2没有自己的catch方法,就会调用Promise.all()catch方法。

const p1 = new Promise((resolve, reject) => {
  resolve('hello');
})
.then(result => result);

const p2 = new Promise((resolve, reject) => {
  throw new Error('报错了');
})
.then(result => result);

Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// Error: 报错了

题5:

考点:立即resolve()的 Promise 对象,是在本轮“事件循环”(event loop)的结束时执行,而不是在下一轮“事件循环”的开始时

setTimeout(function () {
  console.log('three');
}, 0);

Promise.resolve().then(function () {
  console.log('two');
});

console.log('one');

// one
// two
// three

题5

考点:Promise 新建后就会立即执行。promise1没有被resolve或者reject,因此状态还是pending

const promise1 = new Promise((resolve, reject) => {
  console.log('promise1')
})
console.log('1', promise1);

// promise1
// 1 Promise{<Pending>} 

题6

考点:promise的状态可有resolve和reject决定。同步任务和异步任务的执行顺序。

const promise = new Promise((resolve, reject) => {
    console.log(1);  
    resolve('success')// 返回了resolve,在后面的then中就能执行
    console.log(2); 
}); 
promise.then(() => {  
    console.log(3); 
}); 
console.log(4);

// 1
// 2
// 4
// 3

题7

考点:在promise中并没有resolve或者reject.因此promise.then并不会执行,它只有在被改变了状态之后才会执行

const promise = new Promise((resolve, reject) => {
    console.log(1);  
    console.log(2); 
    // 没有resolve返回,仍处于pending状态,不进入.then
}); 
promise.then(() => {  
    console.log(3); 
}); 
console.log(4);
// 1
// 2
// 4

题8

考点:promise实例返回格式,微任务队列执行顺序,promise改变状态的时机

const promise1 = new Promise((resolve, reject) => {
  console.log('promise1') // 新建promise,立即执行
  resolve('resolve1') // 将promise1的状态改成resolved,并将结果保存下来
})
const promise2 = promise1.then(res => { // promise1.then 放入微任务队列
  console.log(res)
    // 无resolve和reject 状态为pending的新的promise
})
console.log('1', promise1); // 立即执行同步任务,拿到promise1的状态
console.log('2', promise2);// 立即执行同步任务,拿到promise2的状态
// 将微任务队列的结果返回

// promise1
// 1,Promise{<Resolved>: 'resolve1'}
// 2,Promise{<Pending>}
// resolve1

题9

考点:fn函数它是直接返回了一个new Promise的,而且fn函数的调用是在start之前,所以它里面的内容应该会先执行。

const fn = () => (new Promise((resolve, reject) => {
  console.log(1);
  resolve('success')
})) // 一个函数,1 先打印
fn().then(res => { // 函数被调用了
  console.log(res)
})
console.log('start')
// 1
// start
// success

题10

考点:Promise 新建后就会立即执行。注意它是不是被包裹在函数当中,如果是的话,只有在函数调用的时候才会执行。

const fn = () =>
  new Promise((resolve, reject) => {
    console.log(1);
    resolve("success");
  });
console.log("start");
fn().then(res => {
  console.log(res);
});

// start
// 1
// success

题11

考点:宏任务与微任务的执行顺序。

console.log('start') // 宏任务
setTimeout(() => { // 下一个宏任务队列执行
  console.log('time')
})
Promise.resolve().then(() => {
  console.log('resolve') // 微任务
})
console.log('end') // 宏任务

// start
// end
// resolve
// time

题12

const promise = new Promise((resolve, reject) => {
  console.log(1); // 立即执行宏任务打印
  setTimeout(() => { // 定时器,放入下一个宏任务的延迟队列中等待执行
    console.log("timerStart");
    resolve("success");
    console.log("timerEnd");
  }, 0);
  console.log(2); // 执行,resolve即使调用了也不会终止
});
promise.then((res) => { // 微任务,其状态还是为pending,这里理解为先不执行。依赖定时器的结果
  console.log(res);
});
console.log(4); // 立即执行
// 一轮循环过后,进入第二次宏任务,发现延迟队列中有setTimeout定时器,执行定时器的内容
// 1
// 2
// 4
// timerStart
// timerEnd
// success

题13

考点:promise.then()是微任务,在本轮宏仁务执行完后,执行其存在的微任务队列。setTimeout宏仁务,但再下一轮宏仁务队列中执行。

setTimeout(() => {
  console.log('timer1');
  setTimeout(() => { // 定时器timer3的话,它会在timer2后执行
    console.log('timer3')
  }, 0)
}, 0)
setTimeout(() => {
  console.log('timer2')
}, 0)
console.log('start')
// start
// timer1
// timer2
// timer3
setTimeout(() => {
  console.log('timer1');
  Promise.resolve().then(() => { // Promise.then却是在timer2之前执行
    console.log('promise')
  })
}, 0)
setTimeout(() => {
  console.log('timer2')
}, 0)
console.log('start')

// start
// timer1
// promise
// timer2

题14

Promise.resolve().then(() => { // 放入本轮微任务队列1
  console.log('promise1'); // 宏仁务2
  const timer2 = setTimeout(() => { // 下一次宏仁务3,等待执行
    console.log('timer2')
  }, 0)
});
const timer1 = setTimeout(() => { 
  console.log('timer1') // 立即执行 
  Promise.resolve().then(() => { // 下一次宏仁务执行,在执行下一次微任务队列
    console.log('promise2')
  })
}, 0)
console.log('start');// 本轮宏仁务1立即执行

// start
// promise1
// timer1
// promise2
// timer2

题15

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => { // 放入下一轮,宏2
    resolve('success')
  }, 1000)
})
const promise2 = promise1.then(() => { // 微任务,状态为pending,等待执行
  throw new Error('error!!!')
})
console.log('promise1', promise1)// 立即执行,打印
console.log('promise2', promise2)// 立即执行,打印
setTimeout(() => { // 放入下一轮,宏3
  console.log('promise1', promise1)
  console.log('promise2', promise2)
}, 2000)

// promise1,Promise{<Pending>}
// promise2,Promise{<Pending>} 会报错
// promise1,Promise{<fulfilled>: "success"}
// promise2,Promise{<rejected>: Error: error!!!}

题16

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!!!}

题17

考点: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);
  })

// then: success1

题18

考点:catch不管被连接到哪里,都能捕获上层未捕捉过的错误。catch()也会返回一个Promise,且由于这个Promise没有返回值,所以打印出来的是undefined

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:error
// then3:undefined

题19

Promise.resolve(1)
  .then(res => {
    console.log(res);
    return 2; // 会被包装为	resolve(2)
  })
  .catch(err => {
    return 3;
  })
  .then(res => {
    console.log(res);
  });

// 1
// 2

题20

Promise.reject(1)
  .then(res => {
    console.log(res);
    return 2;
  })
  .catch(err => {
    console.log(err);
    return 3
  })
  .then(res => {
    console.log(res);
  });

// 1
// 3

题21

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)
})

// timer
// 1001
// 1002

题22

考点:返回任意一个非 promise 的值都会被包裹成 promise 对象。

因此这里的return new Error('error!!!')也被包裹成了return Promise.resolve(new Error('error!!!'))

Promise.resolve().then(() => {
  return new Error('error!!!') // 重点是return
}).then(res => {
  console.log("then: ", res)
}).catch(err => {
  console.log("catch: ", err)
})

// then: Error:error!!!
// 正常可按照如下2种写法。
return Promise.reject(new Error('error!!!'));
// or
throw new Error('error!!!')

题23

考点:.then.catch 返回的值不能是 promise 本身,否则会造成死循环。

const promise = Promise.resolve().then(() => {
  return promise;
})
promise.catch(console.err)
// Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>

题24

考点:.then 或者 .catch 的参数期望是函数,传入非函数则会发生值透传

Promise.resolve(1)
  .then(2) // 数字类型
  .then(Promise.resolve(3)) // 对象
  .then(console.log)
// 1

题25

考点:链式调用后面的内容需要等前一个调用执行完才会执行。

就像是这里的finally()会等promise1().then()执行完才会将finally()加入微任务队列,其实如果这道题中你把finally()换成是then()也是这样的

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
// 1
// error
// finally1
// finally2