关于Promise

220 阅读17分钟
# Promise

参考:
阮一峰ES6
Promise手写实践
你不知道的JavaScript(中)

我们知道,JS是单线程,一次只能执行一个任务,如果有多个任务就要排队,一个任务完成以后继续下一个任务,但是发送请求获取数据是需要时间的,因此异步编程就成了一个热点,使用异步可以使得js在等待的这段时间去做其他的事情,传统的异步操作是通过【回调函数和事件】。
但是回调函数有一个致命的缺点,==就是很容易陷入回调地狱,这会造成代码层次复杂可读性差难以维护的问题==。因此ES6原生提供Promise对象统一了江湖上的一些解决方法,将其列入规范,使得异步的操作「近乎」同步化。

1.Promise的含义

所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

Promise对象有以下两个特点。

image

(1)==对象的状态不受外界影响==。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。

(2)==一旦状态改变,就不会再变,任何时候都可以得到这个结果==。Promise对象的状态改变,只有两种可能:从 pending 变为 fulfilled 和从 pending 变为 rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。

有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易。

一个Promise代表了一个操作未来的结果,往往是应用在异步操作上。主要通过then方法,注册回调,接收promise实例的value或者reason。

2.基本用法

ES6 规定,Promise对象是一个构造函数,用来生成Promise实例

const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve 和 reject。

resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去,==可以用then方法分别指定resolved状态和rejected状态的回调函数。==

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

3.链式调用

3.1 then

Promise 实例具有then方法,也就是说,then方法是定义在原型对象Promise.prototype上的。它的作用是为 Promise 实例添加状态改变时的回调函数。前面说过,then方法的第一个参数是resolved状态的回调函数,第二个参数是rejected状态的回调函数,它们都是可选的。

直接看拓展后的代码,再去推导then的作用

var p = Promise.resolve( 21 ); 

p.then(function(v){ 
    console.log(v); 
    // 创建一个promise并返回
    return new Promise( function(resolve,reject){ 
        // 引入异步!
        setTimeout( function(){ 
        // 用值42填充
         resolve( v * 2 ); 
         }, 100 ); 
    }); 
}) 
.then(function(v){ 
    console.log( v );
});

v 的第一个log值 21 ;第二个log值 42
==说明第二个then是在前一步中的100ms延迟之后运行的==

这种强大实在不可思议!在这些例子中,一步步传递的值是可选的。如果不显式返回一个值,就会隐式返回 undefined,并且这些 promise 仍然会以同样的方式链接在一起。这样,每个 Promise 的决议就成了继续下一个步骤的信号。

通俗一点来说

  • Promise对象的then方法返回的是一个新的Promise对象。
  • 后面的then方法就是在为上一个then返回的Promise注册回调。
  • 前面then方法中回调函数的返回值会作为后面then方法回调的参数。
  • 如果回调中返回的是Promise,那后面then方法的回调会等待它的结束。

3.2. 错误处理catch

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

如果 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

还是那个道理,==因为 Promise 的状态一旦改变,就永久保持该状态,不会再变了。==

catch()方法返回的还是一个 Promise 对象,因此后面还可以接着调用then()方法。

const someAsyncThing = function() {
  return new Promise(function(resolve, reject) {
    // 下面一行会报错,因为x没有声明
    resolve(x + 2);
  });
};

someAsyncThing()
.catch(function(error) {
  console.log('oh no', error);
})
.then(function() {
  console.log('carry on');
});
// oh no [ReferenceError: x is not defined]
// carry on

上面代码运行完catch()方法指定的回调函数,会接着运行后面那个then()方法指定的回调函数。如果没有报错,则会跳过catch()方法。

3.3 Promise.prototype.finally()

finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。

promise  
.then(result => {···})
.catch(error => {···})
.finally(() => {···});

上面代码中,不管promise最后的状态,在执行完then或catch指定的回调函数以后,都会执行finally方法指定的回调函数。

finally方法的回调函数不接受任何参数,这意味着没有办法知道,前面的 Promise 状态到底是fulfilled还是rejected。这表明,finally方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果

4.相关API

4.1 Promise.all()

Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。

const p = Promise.all([p1, p2, p3]);

Promise.all 等待所有都完成(==或第一个失败==)。

var p1 = Promise.resolve(3);
var p2 = 1337;
var p3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([p1, p2, p3]).then(values => {
  console.log(values); // [3, 1337, "foo"]
});
  • 如果参数中包含非 promise 值,这些值将被忽略,但仍然会被放在返回数组中(如果 promise 完成的话):
  • Promise.all 在任意一个传入的 promise 失败时返回失败。例如,如果你传入的 promise中,有四个 promise 在一定的时间之后调用成功函数,==有一个立即调用失败函数,那么 Promise.all 将立即变为失败==。

4.2 Promise.race()

Promise.race方法同样是将多个Promise实例,包装成一个新的Promise实例。可以传递多个Promise对象作为参数,如果实例红有一个实例率先改变状态,那么race的状态就会跟着改变。

const promise1 = new Promise((resolve, reject) => {
  reject();
})
const promise2 = new Promise((resolve, reject) => {
  resolve();
})
const promise3 = new Promise((resolve, reject) => {
  reject();
})

const promiseRace = Promise.race([promise1, promise2, promise3]).then(res => {
  console.log('race then');
}).catch(error => {
  console.log('race catch');
})

// race catch

有时候,我们希望等到一组异步操作都结束了,不管每一个操作是成功还是失败,再进行下一步操作。但是,现有的 Promise 方法很难实现这个要求。

4.3 Promise.allSettled()

可能会先想到Promise.all(),但是Promise.all()方法只适合所有异步操作都成功的情况,如果有一个操作失败,就无法满足要求。

const resolved = Promise.resolve(42);
const rejected = Promise.reject(-1);

const allSettledPromise = Promise.allSettled([resolved, rejected]);

allSettledPromise.then(function (results) {
  console.log(results);
});
// [
//    { status: 'fulfilled', value: 42 },
//    { status: 'rejected', reason: -1 }
// ]

4.4 Promise.any()

只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。

Promise.any()跟Promise.race()方法很像,只有一点不同,就是Promise.any()不会因为某个 Promise 变成rejected状态而结束,必须等到所有参数 Promise 变成rejected状态才会结束。

var resolved = Promise.resolve(42);
var rejected = Promise.reject(-1);
var alsoRejected = Promise.reject(Infinity);

Promise.any([resolved, rejected, alsoRejected]).then(function (result) {
  console.log(result); // 42
});

Promise.any([rejected, alsoRejected]).catch(function (results) {
  console.log(results); // [-1, Infinity]
});

4.5 Promise.resolve() 和 Promise.reject()

创建一个已被拒绝的 Promise 的快捷方式是使用 Promise.reject(..),所以以下两个 promise 是等价的:

var p1 = new Promise( function(resolve,reject){ 
 reject( "Oops" ); 
} ); 
var p2 = Promise.reject( "Oops" );

Promise.resolve()方法的参数分成四种情况。

(1)参数是一个 Promise 实例

如果参数是 Promise 实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。

(2)参数是一个thenable对象

thenable对象指的是具有then方法的对象,比如下面这个对象。

let thenable = {
  then: function(resolve, reject) {
    resolve(42);
  }
};

Promise.resolve()方法会将这个对象转为 Promise 对象,然后就立即执行thenable对象的then()方法。

let thenable = {
  then: function(resolve, reject) {
    resolve(42);
  }
};

let p1 = Promise.resolve(thenable);
p1.then(function (value) {
  console.log(value);  // 42
});

上面代码中,thenable对象的then()方法执行后,对象p1的状态就变为resolved,从而立即执行最后那个then()方法指定的回调函数,输出42。

(3)参数不是具有then()方法的对象,或根本就不是对象

如果参数是一个原始值,或者是一个不具有then()方法的对象,则Promise.resolve()方法返回一个新的 Promise 对象,状态为resolved。

const p = Promise.resolve('Hello');

p.then(function (s) {
  console.log(s)
});
// Hello

上面代码生成一个新的 Promise 对象的实例p。由于字符串Hello不属于异步操作(判断方法是字符串对象不具有 then 方法),返回 Promise 实例的状态从一生成就是resolved,所以回调函数会立即执行。Promise.resolve()方法的参数,会同时传给回调函数。

(4)不带有任何参数

Promise.resolve()方法允许调用时不带参数,直接返回一个resolved状态的 Promise 对象。

所以,如果希望得到一个 Promise 对象,比较方便的方法就是直接调用Promise.resolve()方法。

const p = Promise.resolve();

p.then(function () {
  // ...
});

上面代码的变量p就是一个 Promise 对象。

5.小试牛刀

题目一

const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log('once')
        resolve('success')
    }, 1000)
 })
promise.then((res) => {
    console.log(res)
})
promise.then((res) => {
    console.log(res)
 })

promise的构造函数只会执行一次,而then方法可以多次调用,但是第二次是直接返回结果,不会有异步等待的时间,所以执行结果是: 过一秒打印:once,success,success。

题目二

const promise = new Promise((resolve, reject) => {
    console.log(1);
    resolve();
    console.log(2);
    reject('error');
})
promise.then(() => {
    console.log(3);
}).catch(e => console.log(e))
console.log(4);

解析:规则一,promise构造函数的代码会立即执行,then或者reject里面的代码会放入异步微任务队列,在宏任务结束后会立即执行。规则二:promise的状态一旦变更为成功或者失败,则不会再次改变,所以执行结果为:1,2,4,3。而catch里面的函数不会再执行。

6.手写Promise

下面代码是Promise基本用法的代码实现

1、Promise 的声明

首先呢,promise肯定是一个类,我们就用class来声明。 • 由于 new Promise((resolve, reject)=>{}) ,所以传入一个参数(函数),秘籍里叫他executor,传入就执行。 •executor里面有两个参数,一个叫resolve(成功),一个叫reject(失败)。 •由于resolve和reject可执行,所以都是函数,我们用let声明。

class Promise{
  // 构造器
  constructor(executor){
    // 成功
    let resolve = () => { };
    // 失败
    let reject = () => { };
    // 立即执行
    executor(resolve, reject);
  }
}

2、解决基本状态

秘籍对Promise有规定:

•Promise存在三个状态(state)pending、fulfilled、rejected

•pending(等待态)为初始态,并可以转化为fulfilled(成功态)和rejected(失败态)

•成功时,不可转为其他状态,且必须有一个不可改变的值(value)

•失败时,不可转为其他状态,且必须有一个不可改变的原因(reason)

• new Promise((resolve, reject)=>{resolve(value)}) resolve为成功,接收参数value,状态改变为fulfilled,不可再次改变。

• new Promise((resolve, reject)=>{reject(reason)}) reject为失败,接收参数reason,状态改变为rejected,不可再次改变。

•若是executor函数报错 直接执行reject();

于是乎,我们获得以下代码:

class Promise{
  static PENDING = '待定'
  static FULFILLED = '成功'
  static REJECTED = '拒绝'
  
  constructor(executor){
    this.Status = Commitment.PENDING
    this.Result = null
    this.ResloveCallBacks = []
    this.RejectCallBacks = []
    
    let resolve = value => {
      // state改变,resolve调用就会失败
      if (this.Status === Commitment.PENDING) {
        this.Status = Commitment.FULFILLED
        this.Result = value
      }
    };
    let reject = reason => {
      // state改变,reject调用就会失败
      if (this.Status === Commitment.PENDING) {
        this.Status = Commitment.REJECTED
        this.Result = value
      }
    };
    // 如果executor执行报错,直接执行reject
    try{
      executor(resolve, reject);
    } catch (err) {
      reject(err);
    }
  }
}

3、then方法

秘籍规定:Promise有一个叫做then的方法,里面有两个参数:onFulfilled,onRejected,成功有成功的值,失败有失败的原因

  • 当状态state为fulfilled,则执行onFulfilled,传入this.value。当状态state为rejected,则执行onRejected,传入this.value
  • onFulfilled,onRejected如果他们是函数,则必须分别在fulfilled,rejected后被调用,value或reason依次作为他们的第一个参数
class Promise{
  constructor(executor){...}
  // then 方法 有两个参数onFulfilled onRejected
  then(onFulfilled,onRejected) {
    // 状态为fulfilled,执行onFulfilled,传入成功的值
    if (this.Status === Commitment.FULFILLED) {
      onFulfilled(this.Result);
    };
    // 状态为rejected,执行onRejected,传入失败的原因
    if (this.Status === Commitment.REJECTED) {
      onRejected(this.Result);
    };
  }
}

4、解决异步实现

现在基本可以实现简单的同步代码,但是当resolve在setTomeout内执行,then时state还是pending等待状态 我们就需要在then调用的时候,将成功和失败存到各自的数组,一旦reject或者resolve,就调用它们 类似于发布订阅,先将then里面的两个函数储存起来,由于一个promise可以有多个then,所以存在同一个数组内。

class Promise{
  constructor(executor){
    this.Status = Commitment.PENDING
    this.Result = null
    this.ResloveCallBacks = []
    this.RejectCallBacks = []
    let resolve = value => {
        if (this.Status === Commitment.PENDING) {
            this.Status = Commitment.FULFILLED
            this.Result = value
            this.ResloveCallBacks.forEach(callback => {
                callback(value)
            })
        }
    };
    let reject = value => {
        if (this.Status === Commitment.PENDING) {
            this.Status = Commitment.REJECTED
            this.Result = value
            this.RejectCallBacks.forEach(callback => {
                callback(value)
            })
        }
    };
    try{
      executor(resolve, reject);
    } catch (err) {
      reject(err);
    }
  }
  then(onFulfilled,onRejected) {
    if (this.Status === Commitment.FULFILLED) {
      onFulfilled(this.value);
    };
    if (this.Status === Commitment.REJECTED) {
      onRejected(this.reason);
    };
    if (this.Status === Commitment.PENDING) {
      // onFulfilled传入到成功数组
      this.ResloveCallBacks.push(()=>{
        onFulfilled(this.Result);
      })
      // onRejected传入到失败数组
      this.RejectCallBacks.push(()=>{
        onRejected(this.Result);
      })
    }
  }
}

5、解决链式调用

我门常常用到 new Promise().then().then() ,这就是链式调用,用来解决回调地狱

1、为了达成链式,我们默认在第一个then里返回一个promise。秘籍规定了一种方法,就是在then里面返回一个新的promise,称为promise2: promise2 = new Promise((resolve, reject)=>{}) •将这个promise2返回的值传递到下一个then中 •如果返回一个普通的值,则将普通的值传递给下一个then中

2、当我们在第一个then中 return 了一个参数(参数未知,需判断)。这个return出来的新的promise就是onFulfilled()或onRejected()的值

秘籍则规定onFulfilled()或onRejected()的值,即第一个then返回的值,叫做x,判断x的函数叫做resolvePromise

class Promise{
  constructor(executor){
    this.state = 'pending';
    this.value = undefined;
    this.reason = undefined;
    this.onResolvedCallbacks = [];
    this.onRejectedCallbacks = [];
    let resolve = value => {
      if (this.state === 'pending') {
        this.state = 'fulfilled';
        this.value = value;
        this.onResolvedCallbacks.forEach(fn=>fn());
      }
    };
    let reject = reason => {
      if (this.state === 'pending') {
        this.state = 'rejected';
        this.reason = reason;
        this.onRejectedCallbacks.forEach(fn=>fn());
      }
    };
    try{
      executor(resolve, reject);
    } catch (err) {
      reject(err);
    }
  }
  then(onFulfilled,onRejected) {
    // 声明返回的promise2
    let promise2 = new Promise((resolve, reject)=>{
      if (this.Status === Commitment.FULFILLED) {
        let x = onFulfilled(this.value);
        resolvePromise(promise2, x, resolve, reject);
      };
      if (this.Status === Commitment.REJECTED) {
        let x = onRejected(this.reason);
        resolvePromise(promise2, x, resolve, reject);
      };
      if (this.Status === Commitment.PENDING) {
        this.ResloveCallBacks.push(()=>{
          let x = onFulfilled(this.value);
          resolvePromise(promise2, x, resolve, reject);
        })
        this.RejectCallBacks.push(()=>{
          let x = onRejected(this.value);
          resolvePromise(promise2, x, resolve, reject);
        })
      }
    });
    // 返回promise,完成链式
    return promise2;
  }
}

6、完成resolvePromise函数

秘籍规定了一段代码,让不同的promise代码互相套用,叫做resolvePromise

  • 如果 x === promise2,则是会造成循环引用,自己等待自己完成,则报“循环引用”错误
let p = new Promise(resolve => {
  resolve(0);
});
var p2 = p.then(data => {
  // 循环引用,自己等待自己完成,一辈子完不成
  return p2;
})

1、判断x

  • Otherwise, if x is an object or function,Let then be x.then
  • x 不能是null
  • x 是普通值 直接resolve(x)
  • x 是对象或者函数(包括promise), let then = x.then 2、当x是对象或者函数(默认promise)
  • 声明了then
  • 如果取then报错,则走reject()
  • 如果then是个函数,则用call执行then,第一个参数是this,后面是成功的回调和失败的回调
  • 如果成功的回调还是pormise,就递归继续解析 3、成功和失败只能调用一个 所以设定一个called来防止多次调用
const resolvePromise = (promise2, x, resolve, reject) => {
    // x和promise2不能是同一个值,如果是同一个值就报错
    if (promise2 === x) {
        return reject(
            new TypeError('Chaining cycle detected for promise #<promise>')
        )
    }
    // 判断如果x是否是一个对象,判断函数是否是对象的方法有:typeof instanceof constructor toString
    if (typeof x === 'object' && x != null || typeof x === 'function') {
        try {
            let then = x.then // 取then可以报错,报错就走reject()
            if (typeof then === 'function') {
                // 用then.call()为了避免在使用一次x.then报错
                then.call(x, y => {
                    console.log('y', y)
                    //递归调用
                    resolvePromise(x, y, resolve, reject)// 采用promise的成功结果,并且向下传递
                }, r => {
                    reject(r)// 采用promise的失败结果,并且向下传递
                })
            } else {
                resolve(x)// x不是一个函数,是一个对象
            }
        } catch (err) {
            reject(err)
        }
    } else {
        // x是一个普通值
        resolve(x)
    }
}

7、解决其他问题

1、秘籍规定onFulfilled,onRejected都是可选参数,如果他们不是函数,必须被忽略

  • onFulfilled返回一个普通的值,成功时直接等于 value => value
  • onRejected返回一个普通的值,失败时如果直接等于 value => value,则会跑到下一个then中的onFulfilled中,所以直接扔出一个错误 reason => throw err 2、秘籍规定onFulfilled或onRejected不能同步被调用,必须异步调用。我们就用setTimeout解决异步问题
  • 如果onFulfilled或onRejected报错,则直接返回reject()
class Promise{
  constructor(executor){
    this.Status = Commitment.PENDING
    this.Result = null
    this.ResloveCallBacks = []
    this.RejectCallBacks = []
    let resolve = value => {
       if (this.Status === Commitment.PENDING) {
          this.Status = Commitment.FULFILLED
          this.Result = value
          this.ResloveCallBacks.forEach(callback => {
              callback(value)
          })
       }
    };
    let reject = reason => {
      if (this.Status === Commitment.PENDING) {
            this.Status = Commitment.REJECTED
            this.Result = value
            this.RejectCallBacks.forEach(callback => {
            callback(value)
        })
       }
    };
    try{
      executor(resolve, reject);
    } catch (err) {
      reject(err);
    }
  }
  then(onFulfilled,onRejected) {
    // onFulfilled如果不是函数,就忽略onFulfilled,直接返回value
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    // onRejected如果不是函数,就忽略onRejected,直接扔出错误
    onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
    let promise2 = new Promise((resolve, reject) => {
      if (this.Status === Commitment.FULFILLED) {
        // 异步
        setTimeout(() => {
          try {
            let x = onFulfilled(this.Result);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      };
      if (this.Status === Commitment.REJECTED) {
        // 异步
        setTimeout(() => {
          // 如果报错
          try {
            let x = onRejected(this.Result);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      };
      if (this.Status === Commitment.PENDING) {
        this.ResloveCallBacks.push(() => {
          // 异步
          setTimeout(() => {
            try {
              let x = onFulfilled(this.Result);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0);
        });
        this.RejectCallBacks.push(() => {
          // 异步
          setTimeout(() => {
            try {
              let x = onRejected(this.Result);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0)
        });
      };
    });
    // 返回promise,完成链式
    return promise2;
  }
}

下面是完整的Promise实现代码

class Commitment {
    static PENDING = '待定'
    static FULFILLED = '成功'
    static REJECTED = '拒绝'

    constructor(executor) {
        this.Status = Commitment.PENDING
        this.Result = null
        this.ResloveCallBacks = []
        this.RejectCallBacks = []
        let resolve = value => {
            //resolve和reject是在时间循环末尾执行的 加setTimeout
            setTimeout(() => {
                if (this.Status === Commitment.PENDING) {
                    this.Status = Commitment.FULFILLED
                    this.Result = value
                    this.ResloveCallBacks.forEach(callback => {
                        callback(value)
                    })
                }
            });

        }
        let reject = value => {
            setTimeout(() => {
                if (this.Status === Commitment.PENDING) {
                    this.Status = Commitment.REJECTED
                    this.Result = value
                    this.RejectCallBacks.forEach(callback => {
                        callback(value)
                    })
                }
            });
        }
        try {
            executor(resolve, reject)
        } catch (error) {
            reject(error)
        }

    }
    then(onFulfilled, onRejected) {
        // onFulfilled如果不是函数,就忽略onFulfilled,直接返回value
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
        // onRejected如果不是函数,就忽略onRejected,直接扔出错误
        onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
        let promise2 = new Promise((resolve, reject) => {
            if (this.Status === Commitment.FULFILLED) {
                // 异步
                setTimeout(() => {
                    try {
                        let x = onFulfilled(this.Result);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                }, 0);
            };
            if (this.Status === Commitment.REJECTED) {
                // 异步
                setTimeout(() => {
                    // 如果报错
                    try {
                        let x = onRejected(this.Result);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                }, 0);
            };
            // 当resolve在setTomeout内执行,then时state还是pending等待状态 我们就需要在then调用的时候,将成功和失败存到各自的数组,一旦reject或者resolve,就调用它们
            // 类似于发布订阅,先将then里面的两个函数储存起来,由于一个promise可以有多个then,所以存在同一个数组内。
            if (this.Status === Commitment.PENDING) {
                this.ResloveCallBacks.push(() => {
                    // 异步
                    setTimeout(() => {
                        try {
                            let x = onFulfilled(this.Result);
                            resolvePromise(promise2, x, resolve, reject);
                        } catch (e) {
                            reject(e);
                        }
                    }, 0);
                });
                this.RejectCallBacks.push(() => {
                    // 异步
                    setTimeout(() => {
                        try {
                            let x = onRejected(this.Result);
                            resolvePromise(promise2, x, resolve, reject);
                        } catch (e) {
                            reject(e);
                        }
                    }, 0)
                });
            };
        });
        // 返回promise,完成链式
        return promise2;
    }
}

const resolvePromise = (promise2, x, resolve, reject) => {
    // x和promise2不能是同一个人,如果是同一个人就报错
    if (promise2 === x) {
        return reject(
            new TypeError('Chaining cycle detected for promise #<promise>')
        )
    }
    // 判断如果x是否是一个对象,判断函数是否是对象的方法有:typeof instanceof constructor toString
    if (typeof x === 'object' && x != null || typeof x === 'function') {
        try {
            let then = x.then // 取then可以报错,报错就走reject()
            if (typeof then === 'function') {
                // 用then.call()为了避免在使用一次x.then报错
                then.call(x, y => {
                    console.log('y', y)
                    //递归调用
                    resolvePromise(x, y, resolve, reject)// 采用promise的成功结果,并且向下传递
                }, r => {
                    reject(r)// 采用promise的失败结果,并且向下传递
                })
            } else {
                resolve(x)// x不是一个函数,是一个对象
            }
        } catch (err) {
            reject(err)
        }
    } else {
        // x是一个普通值
        resolve(x)
    }
}

大家可以跟着 史上最最最详细的手写Promise教程 这篇文章,按步骤手写一边Promise,更加方便与记忆和理解。