promise源码解析

135 阅读7分钟

在介绍promise之前我们先看一道面试题。

console.log(1) 
const test = () => {
  console.log(3)
  return 4
}
const promise = new Promise((resole, reject) => {
  console.log(2)
  resole(test())
})
promise.then(res => {
  console.log(res)
}) 
console.log(5)

答案为: 1 2 3 5 4 从答案我们可以看出promise本身是一个同步函数,其原型上的then方法才是异步执行的。 我们都知道promise的出现解决了ajax回调地狱的问题,那为什么promis可以解决回调地狱问题呢?接下来通过从0到1实现promise来理解这一问题。

手写开始

我们先分析一下promise的基本原理

  1. Promise本质上是一个构造函数, 在执行这个构造函数传入一个函数执行器,并且该执行器会立即执行。
  2. promise内部维护三个状态,且状态不可逆。pengding -> Fulfilled、pengding -> Rejected
  • Pending 等待
  • Fulfilled 完成
  • Rejected 失败
  1. Promise 中使用 resolve 和 reject 两个函数来更改状态;

1、下面开始实现

// 先定义三个状态

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MyPromise{
  // executor: 传入的执行器函数,会立即执行
  constructor(executor) {

    this.value = null;  // 接收成功的值
    this.reason = null; // 接受失败的原因
    this.status = PENDING; // 初始状态

    executor(this.resolve, this.reject) // 执行器执行
  }
  // 这里需要用箭头函数,要不拿不到this
  resolve = (value) => {
    if(this.status !== PENDING) return ; // 只有状态为等待才能修改
    this.status = FULFILLED; // 状态改为成功
    this.value = value; // 保存成功的值
  }
  // 这里需要用箭头函数,要不拿不到this
  reject = (reason) => {
    if(this.status !== PENDING) return ; // 只有状态为等待才能修改
    this.status = REJECTED; // 状态改为失败
    this.reason = reason; // 保存失败的值
  }

  then(onFulfilled, onRejected) {
    if(this.status === FULFILLED) {
      onFulfilled(this.value)
    } else if(this.status === REJECTED){
      onRejected(this.reason)
    }
  }
}

// 测试

const promise = new MyPromise((resole, reject) => {
  resole('执行成功回调')
})

promise.then((res) => {
  console.log(res)
}, (err) => {
  console.log(err)
})

2、加入异步逻辑

上面写的都是同步的逻辑,then函数也是异步的,所以接下来我们开始增加异步逻辑代码。

// 测试

const promise = new MyPromise((resole, reject) => {
  setTimeout(() => {
    resole('执行成功回调')
  }, 0) // 这里改成异步
})

promise.then((res) => {
  console.log(res)
}, (err) => {
  console.log(err)
})

上述代码执行是不会打印“执行成功回调”的,这是因为当执行原型上的then方法时,状态还是PENDING。所以此时我们应该把then传入的方法储存起来,等到状态改变之后再去执行。

constructor(executor) {

    this.value = null;  // 接收成功的值
    this.reason = null; // 接受失败的原因
    this.status = PENDING; // 初始状态
   +this.onFulfilledCallback = []; // 储存成功的回调
   +this.onRejectedCallback = []; // 存储失败的回调

    executor(this.resolve, this.reject) // 执行器执行
  }

改造resolve、reject方法

resolve = (value) => {
    if(this.status !== PENDING) return ; // 只有状态为等待才能修改
    this.status = FULFILLED; // 状态改为成功
    this.value = value; // 保存成功的值
   +this.onFulfilledCallback.forEach(callback => callback()); // 状态改变,执行onFulfilledCallback数组储存的函数
  }
reject = (reason) => {
    if(this.status !== PENDING) return ; // 只有状态为等待才能修改
    this.status = REJECTED; // 状态改为失败
    this.reason = reason; // 保存失败的值
   +this.onRejectedCallback.forEach(callback => callback()); // 状态改变,执行onRejectedCallback数组储存的函数
  }

改造then方法

then(onFulfilled, onRejected) {
    if(this.status === FULFILLED) {
      setTimeout(() => { // then是异步的
        onFulfilled(this.value); // 执行成功的回调
      }, 0)
    } else if(this.status === REJECTED){
      setTimeout(() => { // then是异步的
        onRejected(this.reason); // 执行失败的回调
      }, 0)
      
    }else{
      // 当状态为Pending是分别用onFulfilledCallback、onRejectedCallback储存成功、失败的回调
      this.onFulfilledCallback.push(() => {
        setTimeout(() => { 
          onFulfilled(this.value); // 执行成功的回调
        }), 0
      })
      this.onRejectedCallback.push(() => {
        setTimeout(() => {
          onRejected(this.reason); // 执行失败的回调
        }, 0)
      })
    }
  }

3、promise的then方法可以链式调用(因此其应该返回一个promise实例,事实上promise的其它方法如:原型上的catch,静态方法all,race,resole,reject,allSettled,等等都应该返回一个新的promise实例,下文会一一介绍)

改造then方法

  then(onFulfilled, onRejected) {
    // 实现then链式调用
    const resPromise = (p, s, resolve, reject) => {
      if(p === s) {
        return reject(new TypeError('Chaining cycle detected for promise'));
      }
      if(s instanceof MyPromise) {
        s.then(resolve, reject)
      }else{
        resolve(s)
      }
    }

    let promise = new MyPromise((resolve, reject) => {
      if(this.status === FULFILLED) {
        setTimeout(() => { // then是异步的
          let s = onFulfilled(this.value) // 执行成功的回调, 并且接受上一个promise成功回调返回的值
          resPromise(promise, s, resolve, reject)
        }, 0)
      } else if(this.status === REJECTED){
        setTimeout(() => { // then是异步的
          let s = onRejected(this.reason) //  执行失败的回调,并且接受上一个promise失败回调返回的值
          resPromise(promise, s, resolve, reject)
        }, 0)
        
      }else{
        this.onFulfilledCallback.push(() => {
          setTimeout(() => {
            let s = onFulfilled(this.value); // 执行成功的回调
            resPromise(promise, s, resolve, reject)
          }), 0
        })
        this.onRejectedCallback.push(() => {
          setTimeout(() => {
            let s = onRejected(this.reason); // 执行失败的回调
            resPromise(promise, s, resolve, reject)
          }, 0)
        })
      }
    })
    return promise
  }
}

4、promise其它方法的实现(基于上述实现的then方法实现)

1、原型方法catch的实现

catch(onRejected) {
    return this.then(undefined, onRejected)
  }

2、静态方法resolve、reject

static resolve(value) {
    return new MyPromise((resolve, reject) => {
      if(resolve instanceof MyPromise) {
        value.then(resolve, reject)
      }else {
        resolve(value)
      }
    })
  }

  static reject(reason) {
    return new MyPromise((resolve, reject) => {
      resolve(reason)
    })
  }

3、静态方法all、race

all,race两个方法都接收一个数组,all需要数组内所有的promise都成功才会返回成功的值,该值是所有实例的成功之后值的集合,race返回的是最先完成的promise实例的值,无论成功与否

static all(promises) {
    let len = promises.length;
    let arr = []
    promises = promises.map(p => p instanceof MyPromise ? p : this.resolve(p)); // 不是promise实例就先转化为promise实例
    return new MyPromise((resolve, reject) => {
      for(let i = 0; i < len; i++) {
        promises[i].then(res => {
          arr[i] = res;
          if(arr.length === len) { // 等promises数组所有的实例都返回成功,才resolve
            resolve(arr);
          }
        }, (err) => {
          reject(err); // 只要有一个实例失败,就返回失败
        })
      }
    })
  }

  static race(promises) {
    let len = promises.length;
    promises = promises.map(p => p instanceof MyPromise ? p : this.resolve(p));
    return new MyPromise((resolve, reject) => {
      for(let i = 0; i < len; i++) {
        promises[i].then((res) => resolve(res), (err) => reject(err)); // 无论成功与否,只返回第一个完成的promise
      }
    })
  }

4、静态方法allSettled

allSettled也是接受一个数组,但与all不一样的是,它返回的是数组所有promise返回值的集合。

static allSettled(promises) {
    let len = promises.length;
    let arr = []
    promises = promises.map(p => p instanceof MyPromise ? p : this.resolve(p));
    return new MyPromise((resolve, reject) => {
      for(let i = 0; i < len; i++) {
        promises[i].then((res) => {
          arr[i] = {
            status: 'fulfilled',
            value: res
          }
          if(arr.length === len) resolve(arr); // 当数组遍历完才更改promise状态为成功
        }, (err) => {
          arr[i] = {
            status: 'rejected',
            value: err
          };
          if(arr.length === len) resolve(arr); // 当数组遍历完才更改promise状态为成功
        })
      }
    })
  }

5、静态方法any

该方法也是接受一个数组,与all方法相反,它只要有一个promise状态为fulfilled就返回成功状态,当所有的promise都失败才会返回失败的状态。

static any(promises) {
    let len = promises.length;
    let arr = []
    promises = promises.map(p => p instanceof MyPromise ? p : this.resolve(p));
    for(let i = 0; i < len; i++) {
      promises[i].then(res => {
        resolve(res); // 只要有一个promise成功,就resole,返回成功状态
      }, (err) => {
        arr[i] = err;
        if(arr.length === len) { // 等promises数组所有的实例都返回失败,才reject, 返回失败状态
          reject(arr);
        }
      })
    }
  }

完整代码

// console.log(1)
// const test = () => {
//   console.log(3)
//   return 4
// }
// const promise = new Promise((resole, reject) => {
//   console.log(2)
//   resole(test())
// })
// promise.then(res => {
//   console.log(res)
// }) 
// console.log(5)


// 先定义三个状态

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';



class MyPromise{
  // executor: 传入的执行器函数,会立即执行
  constructor(executor) {

    this.value = null;  // 接收成功的值
    this.reason = null; // 接受失败的原因
    this.status = PENDING; // 初始状态
    this.onFulfilledCallback = []; // 储存成功的回调
    this.onRejectedCallback = []; // 存储失败的回调

    executor(this.resolve, this.reject) // 执行器执行
  }

  resolve = (value) => {
    if(this.status !== PENDING) return ; // 只有状态为等待才能修改
    this.status = FULFILLED; // 状态改为成功
    this.value = value; // 保存成功的值
    this.onFulfilledCallback.forEach(callback => callback()); // 状态改变,执行onFulfilledCallback数组储存的函数
  }

  reject = (reason) => {
    if(this.status !== PENDING) return ; // 只有状态为等待才能修改
    this.status = REJECTED; // 状态改为失败
    this.reason = reason; // 保存失败的值
    this.onRejectedCallback.forEach(callback => callback()); // 状态改变,执行onRejectedCallback数组储存的函数
  }

  then(onFulfilled, onRejected) {
    const resPromise = (p, s, resolve, reject) => {
      if(p === s) {
        return reject(new TypeError('Chaining cycle detected for promise'));
      }
      if(s instanceof MyPromise) {
        s.then(resolve, reject)
      }else{
        resolve(s)
      }
    }

    let promise = new MyPromise((resolve, reject) => {
      if(this.status === FULFILLED) {
        setTimeout(() => { // then是异步的
          let s = onFulfilled(this.value);
          resPromise(promise, s, resolve, reject); // 执行成功的回调
        }, 0)
      } else if(this.status === REJECTED){
        setTimeout(() => { // then是异步的
          let s = onRejected(this.reason);
          resPromise(promise, s, resolve, reject); // 执行失败的回调
        }, 0)
        
      }else{
        this.onFulfilledCallback.push(() => {
          setTimeout(() => {
            let s = onFulfilled(this.value); // 执行成功的回调
            resPromise(promise, s, resolve, reject);
          }), 0
        })
        this.onRejectedCallback.push(() => {
          setTimeout(() => {
            let s = onRejected(this.reason); // 执行失败的回调
            resPromise(promise, s, resolve, reject);
          }, 0)
        })
      }
    })
    return promise;
  }

  catch(onRejected) {
    return this.then(undefined, onRejected);
  }

  static resolve(value) {
    return new MyPromise((resolve, reject) => {
      if(resolve instanceof MyPromise) {
        value.then(resolve, reject);
      }else {
        resolve(value);
      }
    })
  }

  static reject(reason) {
    return new MyPromise((resolve, reject) => {
      resolve(reason);
    })
  }

  static all(promises) {
    let len = promises.length;
    let arr = []
    promises = promises.map(p => p instanceof MyPromise ? p : this.resolve(p)); // 不是promise实例就先转化为promise实例
    return new MyPromise((resolve, reject) => {
      for(let i = 0; i < len; i++) {
        promises[i].then(res => {
          arr[i] = res;
          if(arr.length === len) { // 等promises数组所有的实例都返回成功,才resolve
            resolve(arr);
          }
        }, (err) => {
          reject(err); // 只要有一个实例失败,就返回失败
        })
      }
    })
  }

  static race(promises) {
    let len = promises.length;
    promises = promises.map(p => p instanceof MyPromise ? p : this.resolve(p));
    return new MyPromise((resolve, reject) => {
      for(let i = 0; i < len; i++) {
        promises[i].then((res) => resolve(res), (err) => reject(err)) // 无论成功与否,只返回第一个完成的promise
      }
    })
  }

  static allSettled(promises) {
    let len = promises.length;
    let arr = []
    promises = promises.map(p => p instanceof MyPromise ? p : this.resolve(p));
    return new MyPromise((resolve, reject) => {
      for(let i = 0; i < len; i++) {
        promises[i].then((res) => {
          arr[i] = {
            status: 'fulfilled',
            value: res
          }
          if(arr.length === len) resolve(arr); // 当数组遍历完才更改promise状态为成功
        }, (err) => {
          arr[i] = {
            status: 'rejected',
            value: err
          };
          if(arr.length === len) resolve(arr); // 当数组遍历完才更改promise状态为成功
        })
      }
    })
  }

  static any(promises) {
    let len = promises.length;
    let arr = []
    promises = promises.map(p => p instanceof MyPromise ? p : this.resolve(p));
    for(let i = 0; i < len; i++) {
      promises[i].then(res => {
        resolve(res); // 只要有一个promise成功,就resole,返回成功状态
      }, (err) => {
        arr[i] = err;
        if(arr.length === len) { // 等promises数组所有的实例都返回失败,才reject, 返回失败状态
          reject(arr);
        }
      })
    }
  }




}

// 测试

const promise = new MyPromise((resole, reject) => {
  // resole('执行成功回调')
  reject('执行失败回调')
})


// promise.then((res) => {
//   console.log(res)
//   return '链式调用'
// }, (err) => {
//   console.log(err)
// }).then((res) => {
//   console.log(res)
// })
// console.log('22222222')

// promise.catch((err) => {
//   console.log(err)
//   return 2112
// }).then(res => {
//   console.log(res)
// })