Promise总结

手写Promise

Promise有三个状态:pending,fulfilled,rejected
Promise属性:length(恒为1),prototype
Promise方法:all,race,any,allSettled,resolve,reject
Promise原型上的属性:constructor
Promise原型上的方法:then,catch,finally

(1)Promise只接受一个参数new Promise( function(resolve, reject) {...} /* executor */ );。其中resolve和reject可以任意定义,不过executor中就必须用新定义的名字来作为resolve和reject。

new Promise((a,b)=>a(1));//Promise {: 1}
new Promise((a,b)=>console.log(1));//1 Promise {}
new Promise((a,b)=>1);//Promise {}

(2)第二种情况表明:只要定义了Promise,即使无返回值也会默认返回Promise {}。第三种情况表明:返回原始数据会被直接转化为Promise {}
(3).then() 第一个参数必然是处理 resolve ,第二个参数必然是处理 reject

new Promise((a,b)=>a(1))
.then((res)=>console.log('resolve'),(rej)=>console.log('reject'))
//resolve Promise {: undefined}
new Promise((a,b)=>b(1))
.then((res)=>console.log('resolve'),(rej)=>console.log('reject'))
//reject Promise {: undefined}
//最后返回的 Promise {: undefined} 原因参考下面 MDN 引用

第一个Promise函数返回一个fulfilled状态,then 接收后触发第一个回调函数,输出 'resolve' ,不返回值,因此等于返回一个fulfilled状态的 Promise 。
第二个Promise函数返回一个rejected状态,then 接收后触发第二个回调函数,输出 'reject' ,同样不返回值,因此也等于返回一个fulfilled状态的 Promise 。

MDN 中 .then 返回不同值时的情况:
1.返回了一个值,那么 then 返回的 Promise 将会成为接受状态,并且将返回的值作为接受状态的回调函数的参数值。
2.没有返回任何值,那么 then 返回的 Promise 将会成为接受状态,并且该接受状态的回调函数的参数值为 undefined。
3.抛出一个错误,那么 then 返回的 Promise 将会成为拒绝状态,并且将抛出的错误作为拒绝状态的回调函数的参数值。
4.返回一个已经是接受状态的 Promise,那么 then 返回的 Promise 也会成为接受状态,并且将那个 Promise 的接受状态的回调函数的参数值作为该被返回的Promise的接受状态回调函数的参数值。
5.返回一个已经是拒绝状态的 Promise,那么 then 返回的 Promise 也会成为拒绝状态,并且将那个 Promise 的拒绝状态的回调函数的参数值作为该被返回的Promise的拒绝状态回调函数的参数值。
6.返回一个未定状态(pending)的 Promise,那么 then 返回 Promise 的状态也是未定的,并且它的终态与那个 Promise 的终态相同;同时,它变为终态时调用的回调函数参数与那个 Promise 变为终态时的回调函数的参数是相同的。

(4).catch() 只捕获 reject 状态,如果没有则不执行,如果 .then() 提前捕获了 reject ,并且返回了 resolve 状态(参考上面 .then() 返回不同值的结果),则 .catch() 不执行,因此不推荐 .then() 中捕获 reject ,直接用 .catch() 捕获不容易发生错误。

new Promise((resolve,reject)=>reject(1))//此处返回reject状态
.then((res)=>console.log('resolve'),(rej)=>console.log('reject'))//此处接受reject,无返回值=返回resolve
.then((res)=>console.log('resolve'),(rej)=>console.log('reject'))//此处接受resolve,无返回值=返回resolve
.catch(_=>console.log(_))//接收不到第一个Promise抛出的reject状态
//reject resolve Promise {: undefined}

(5).finally() 不论什么情况一定会触发,用来结尾输出一些必须输出的东西

var isLoading = true;

new Promise((a, b) => a())
.then(_ => console.log('then'))
.finally(_ => isLoading = false);

console.log(isLoading);//false

(6)如果Promise已经resolve变成fulfilled状态,再抛出错误是无效的,如果正常抛出错误或者reject成rejected状态,除非捕获了该状态/错误,否则会一直冒泡传递。

const promise = new Promise(function(resolve, reject) {
  resolve('fulfilled');
  throw new Error('rejected');  //无效的
});
promise
  .then(function(value) { console.log(value) })//未捕获错误,第二个参数为空
  .catch(function(error) { console.log(error) });//这里未执行,代表抛出的错误是无效的
// fulfilled

(7)跟传统的try/catch代码块不同的是,如果没有使用catch()方法指定错误处理的回调函数,Promise 对象抛出的错误不会传递到外层代码,即不会有任何反应。但是尽量用catch()捕获一下错误。

const promise= function() {
  return new Promise(function(resolve, reject) {
    // 下面一行会报错,因为x没有声明
    resolve(x);  //运行到此行抛出错误,但是不会退出进程、终止脚本执行
  });
};

promise().then(function() {//此处then()未捕获reject和错误
  console.log('everything is great');
});

setTimeout(() => { console.log(123) }, 2000);  //依旧会执行
// Uncaught (in promise) ReferenceError: x is not defined
// 123

Promise的方法:
(1)Promise.all(iterable)
所有的Promise完成才完成,或参数中不再存在Promise。任意一个Promise失败,返回第一个失败的Promise.
后面需要接 then() 和 catch() 等方法接住返回的Promise。如果iterable参数中的Promise自带 catch() 捕获了错误,在all中就捕获不到reject,因为 catch() 捕获了错误之后返回的正常情况是resolve。

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

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

(2)Promise.race(iterable)
返回一个 Promise,和第一个传递结果的 Promise 的完成方式相同。

const promise1 = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, '1');
});
const promise2 = new Promise((resolve, reject) => {
  setTimeout(resolve, 200, '2');
});
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, '3');
});

Promise.race([promise1, promise2, promise3]).then((value) => {
  console.log(value);//都是resolve,不过promise3更快
});
// '3'

(3)Promise.any(iterable)
接收第一个 fulfilled 状态的 Promise ,如果全部都是 rejected 状态,那么返回异步失败和 AggregateError

const pErr = new Promise((resolve, reject) => {
  reject("总是失败");
});
const pSlow = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, "最终完成");
});
const pFast = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, "很快完成");
});

Promise.any([pErr, pSlow, pFast]).then((value) => {
  console.log(value);
  // pFast fulfils first
})
// "很快完成"

(4)Promise.allSettled(iterable)
所有Promise都完成后,返回一个对象数组,每个对象表示对应的Promise结果。

const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));
const promises = [promise1, promise2];

Promise.allSettled(promises).
  then((results) => results.forEach((result) => console.log(result.status)));

// "fulfilled"
// "rejected"

(5)Promise.resolve(value)
(6)Promise.reject(reason)

常见面试题

1.Promise如何串行链接

异步执行任务A、B、C...

  1. 使用数组的reduce方法,reduce里有四个参数,pre,next,index,arr,
  2. 如果then方法里返回的是一个promise对象,那么执行下一个then 的时候必定是在上一个then执行完之后执行

代码如下:

var createPromise = function(time) {
    return (resolve, reject)=>
    new Promise((resolve, reject)=>{
        setTimeout(()=>{
            console.log('timein'+time)
            resolve();
        }, time*1000)
    })
}
 
function serpromise(arr) {
    arr.reduce((pre, next, index, carr)=>{
        return pre.then(next)
    }, Promise.resolve())
}
 
var arr=[createPromise(2),createPromise(1),createPromise(3),createPromise(4),createPromise(5)];
// Promise.resolve().then(createPromise(2)).then(createPromise(1))
serpromise(arr)

本人才疏学浅,有错误敬请指出,感激不尽!

参考:
[1]. MDN-Promise
[2]. 【ES6基础知识】promise和await/async
[3].如何实现一个串行promise

你可能感兴趣的:(Promise总结)