实现promise

188 阅读5分钟

实现promise

Promise是ES6中的新的异步语法,解决了回调嵌套的问题:

new Promise((resolve)=>{
  setTimeout(()=>{
    resolve(1)
  },1000)
}).then(val =>{
  console.log(val);
  return new Promise((resolve)=>{
    setTimeout(()=>{
      resolve(2)
    },1000)
  })
}).then(val => {
  console.log(val);
})

实现状态切换

  • promise实例有三个状态,pending,fulfilled,rejected
  • promise实例在构造是可以传入执行函数,执行函数有两个形参resolve,reject可以改变promise的状态,promise的状态一旦改变后不可再进行改变。
  • 执行函数会在创建promise实例时,同步执行
const PENDING = 'PENDING'; // 初始状态
const FULFILLED = 'FULFILLED'; // 成功状态
const REJECTED = 'REJECTED'; // 失败状态
class Promise2 {
  constructor(executor){
    this.status = PENDING
    this.value = null
    this.reason = null
    const resolve = (value) => {
      if (this.status === PENDING) {
        this.value = value;
        this.status = FULFILLED;
      }
    }
    const reject = (reason) => {
      if (this.status === PENDING) {
        this.reason = reason;
        this.status = REJECTED;
      }
    }
    try {
      executor(resolve,reject)
    }catch (e) {
      reject(e)
    }

  }
}
let p = new Promise2((resolve,reject)=>{resolve(1)})

实现then异步执行

promise实例可以调用then方法并且传入回调:

如果调用then时,Promise实例是fulfilled状态,则马上异步执行传入的回调。

如果调用then时,Promise实例是pending状态,传入的回调会等到resolve后再异步执行

例子:

let p = new Promise((resolve, reject)=>{
  console.log(1);
  resolve(2)
  console.log(3);
})
p.then((val)=>{
  console.log(val);
})
//1
//3
//2
let p = new Promise((resolve, reject)=>{
  setTimeout(()=>{
    resolve(1)
  },2000)
})
p.then((val)=>{
  console.log(val);
})

思路:需要用回调先保存到队列中,在resolve后异步执行队列里的回调,在then时判断实例的状态再决定是将回调推入队列,还是直接异步执行回调:

const PENDING = 'PENDING'; // 初始状态
const FULFILLED = 'FULFILLED'; // 成功状态
const REJECTED = 'REJECTED'; // 失败状态
class Promise2 {
  constructor(executor){
    this.status = PENDING
    this.value = null
    this.reason = null
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];
    const resolve = (value) => {
      if (this.status === PENDING) {
        this.value = value;
        this.status = FULFILLED;
        setTimeout(()=>{
          this.onFulfilledCallbacks.forEach(fn => fn(this.value));
        })
      }
    }
    const reject = (reason) => {
      if (this.status === PENDING) {
        this.reason = reason;
        this.status = REJECTED;
        setTimeout(()=>{
          this.onFulfilledCallbacks.forEach(fn => fn(this.reason));
        })
      }
    }
    try {
      executor(resolve,reject)
    }catch (e) {
      reject(e)
    }

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

    }
    if (this.status === PENDING) {
      this.onFulfilledCallbacks.push(onFulfilled); // 存储回调函数
      this.onRejectedCallbacks.push(onRejected); // 存储回调函数
    }
  }
}

resolve Promise实例的情况

resolve的值有可能也是个promise实例,这时候就要用前述实例自己resolve的值

let p = new Promise((resolve,reject) =>{  //promise1
  resolve(new Promise((resolve2,reject2)=>{  //promise2
    setTimeout(()=>{
      resolve2(1)
    },1000)
  }))
})
p.then((val)=>{
  console.log(val);
})

因此需要在promise1的resolve函数中进行判断,是promise实例则在这个promise实例(promise2)后接一个then,并且将promise1的resolve作为回调传入promise2的then

const PENDING = 'PENDING'; // 初始状态
const FULFILLED = 'FULFILLED'; // 成功状态
const REJECTED = 'REJECTED'; // 失败状态
class Promise2 {
  constructor(executor){
    this.status = PENDING
    this.value = null
    this.reason = null
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];
    const resolve = (value) => {
      if (value instanceof this.constructor) {
        value.then(resolve, reject); //resolve reject是箭头函数,this已经绑定到外层Promise
        return
      }
      if (this.status === PENDING) {
        this.value = value;
        this.status = FULFILLED;
        setTimeout(()=>{
          this.onFulfilledCallbacks.forEach(fn => fn(this.value));
        })
      }
    }
    const reject = (reason) => {
      if (this.status === PENDING) {
        this.reason = reason;
        this.status = REJECTED;
        setTimeout(()=>{
          this.onFulfilledCallbacks.forEach(fn => fn(this.reason));
        })
      }
    }
    try {
      executor(resolve,reject)
    }catch (e) {
      reject(e)
    }

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

    }
    if (this.status === PENDING) {
      this.onFulfilledCallbacks.push(onFulfilled); // 存储回调函数
      this.onRejectedCallbacks.push(onRejected); // 存储回调函数
    }
  }
}
let p = new Promise2((resolve,reject) =>{
  resolve(new Promise2((resolve2,reject2)=>{
    setTimeout(()=>{
      resolve2(1)
    },1000)
  }))
})
p.then((val)=>{
  console.log(val);
})

实现链式调用

then可以链式调用,而且前一个then的回调的返回值,如果不是promise实例,则下一个then回调的传参值就是上一个then回调的返回值,如果是promise实例,则下一个then回调的传参值,是上一个then回调返回的promise实例的解决值(value)

let p = new Promise((resolve,reject) =>{
    setTimeout(()=>{
      resolve(1)
    },1000)
})
p.then(val => {
  console.log(val);
  return new Promise((resolve) => {
    setTimeout(()=>{
      resolve(2)
    },1000)
  })
}).then(val => {
  console.log(val);
  return 3
}).then(val => {
  console.log(val);
})

既然能够链式调用,那么then方法本身的返回值必定是一个Promise实例。那么返回的promise实例是不是自身呢?答案显而易见:不是。如果一个promise的then方法的返回值是promise自身,在new一个Promise时,调用了resolve方法,因为promise的状态一旦更改便不能再次更改,那么下面的所有then便只能执行成功的回调,无法进行错误处理,这显然并不符合promise的规范和设计promise的初衷。

因此 then方法会返回一个新的promise实例

const PENDING = 'PENDING'; // 初始状态
const FULFILLED = 'FULFILLED'; // 成功状态
const REJECTED = 'REJECTED'; // 失败状态
class Promise2 {
  constructor(executor){
    this.status = PENDING
    this.value = null
    this.reason = null
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];
    const resolve = (value) => {
      if (value instanceof this.constructor) {
        value.then(resolve, reject); //resolve reject是箭头函数,this已经绑定到外层Promise

        return
      }
      if (this.status === PENDING) {
        this.value = value;
        this.status = FULFILLED;
        setTimeout(()=>{
          this.onFulfilledCallbacks.forEach(fn => fn(this.value));
        })
      }
    }
    const reject = (reason) => {
      if (this.status === PENDING) {
        this.reason = reason;
        this.status = REJECTED;
        setTimeout(()=>{
          this.onFulfilledCallbacks.forEach(fn => fn(this.reason));
        })
      }
    }
    try {
      executor(resolve,reject)
    }catch (e) {
      reject(e)
    }

  }
  then(onFulfilled, onRejected) {
    const promise2 = new this.constructor((resolve, reject) => { // 待返回的新的promise实例
      if (this.status === FULFILLED) {
          setTimeout(()=>{
            try {
              let callbackValue = onFulfilled(this.value);
              resolve(callbackValue);
            }catch(error) {
              reject(error) // 如果出错此次的then方法的回调函数出错,在将错误传递给promise2
            }
          })
      }
      if (this.status === REJECTED) {
        setTimeout(()=>{
          try {
            let callbackValue= onRejected(this.reason);
            resolve(callbackValue);
          } catch (error) {
            reject(error);
          }
        })

      }
      if (this.status === PENDING) {
        this.onFulfilledCallbacks.push(() => {
          try {
            let callbackValue = onFulfilled(this.value);
            resolve(callbackValue);
          }catch (error) {
            reject(error)
          }
        });
        this.onRejectedCallbacks.push(() => {
          try {
            let callbackValue = onRejected(this.reason);
            resolve(callbackValue);
          } catch (error) {
            reject(error);
          }
        });
      }
    })
    return promise2;
  }
}

实现其他方法

  • catch
  • resolve
  • reject
  • all
  • race

方法演示:

/*catch方法*/
let p = new Promise((resolve, reject) => {
  reject(1)
})
p.catch(reason => {
  console.log(reason);
})

/*Promise.resolve*/
let p = Promise.resolve(1)

/*Promise.resolve*/
let p = Promise.reject(1)

/*Promise.all*/
let p = Promise.all([
  new Promise(resolve => {
    setTimeout(() => {
      resolve(1)
    }, 1000)
  }),
  new Promise(resolve => {
    setTimeout(() => {
      resolve(2)
    }, 2000)
  }),
  new Promise(resolve => {
    setTimeout(() => {
      resolve(3)
    }, 3000)
  }),
])
p.then(val => {
  console.log(val);
})
/*Promise.race*/
let p = Promise.race([
  new Promise(resolve => {
    setTimeout(() => {
      resolve(1)
    }, 1000)
  }),
  new Promise(resolve => {
    setTimeout(() => {
      resolve(2)
    }, 2000)
  }),
  new Promise(resolve => {
    setTimeout(() => {
      resolve(3)
    }, 3000)
  }),
])
p.then(val => {
  console.log(val);
})
const PENDING = 'PENDING'; // 初始状态
const FULFILLED = 'FULFILLED'; // 成功状态
const REJECTED = 'REJECTED'; // 失败状态
class Promise2 {

  static resolve(value) {
    if (value instanceof this) {
      return value;
    }
    return new this((resolve, reject) => {
        resolve(value);
    });
  };

  static reject(reason) {
    return new this((resolve, reject) => reject(reason))
  };
  static all(promises){
    return new this((resolve, reject) => {
      let resolvedCounter = 0;
      let promiseNum = promises.length;
      let resolvedValues = new Array(promiseNum);
      for (let i = 0; i < promiseNum; i += 1) {
        Promise2.resolve(promises[i]).then(
          value => {
            resolvedCounter++;
            resolvedValues[i] = value;
            if (resolvedCounter === promiseNum) {
              return resolve(resolvedValues);
            }
          },
          reason => {
            return reject(reason);
          },
        );

      }
    });
  };
  static race(promises){
    return new this((resolve, reject) => {
      if (promises.length === 0) {
        return;
      } else {
        for (let i = 0, l = promises.length; i < l; i += 1) {
          Promise2.resolve(promises[i]).then(
            data => {
              resolve(data);
              return;
            },
            err => {
              reject(err);
              return;
            },
          );
        }
      }
    });
  }
  constructor(executor) {
    this.status = PENDING
    this.value = null
    this.reason = null
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];
    const resolve = (value) => {
      if (value instanceof this.constructor) {
        value.then(resolve, reject); //resolve reject是箭头函数,this已经绑定到外层Promise

        return
      }
      if (this.status === PENDING) {
        this.value = value;
        this.status = FULFILLED;
        setTimeout(() => {
          this.onFulfilledCallbacks.forEach(fn => fn(this.value));
        })
      }
    }
    const reject = (reason) => {
      if (this.status === PENDING) {
        this.reason = reason;
        this.status = REJECTED;
        setTimeout(() => {
          this.onFulfilledCallbacks.forEach(fn => fn(this.reason));
        })
      }
    }
    try {
      executor(resolve, reject)
    } catch (e) {
      reject(e)
    }

  }

  then(onFulfilled, onRejected) {
    const promise2 = new this.constructor((resolve, reject) => { // 待返回的新的promise实例
      if (this.status === FULFILLED) {

        setTimeout(() => {
          try {
            let callbackValue = onFulfilled(this.value);
            resolve(callbackValue);
          } catch (error) {
            reject(error) // 如果出错此次的then方法的回调函数出错,在将错误传递给promise2
          }
        })
      }
      if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            let x = onRejected(this.reason);
            resolve(x);
          } catch (error) {
            reject(error);
          }
        })

      }
      if (this.status === PENDING) {
        this.onFulfilledCallbacks.push(() => {
          try {
            let callbackValue = onFulfilled(this.value);
            resolve(callbackValue);
          } catch (error) {
            reject(error)
          }
        });
        this.onRejectedCallbacks.push(() => {
          try {
            let callbackValue = onRejected(this.reason);
            resolve(callbackValue);
          } catch (error) {
            reject(error);
          }
        });
      }
    })
    return promise2;
  }

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