Promise的实现

199 阅读4分钟
let p = new Promise ((resolve,reject)=>{
	resolve('success');
	reject('fail');
})
p.then(data=>{},fail=>{})

根据上述Promise的基本使用,分析:

  • Promise是一个构造函数
  • Promise接收一个立即执行的函数,且这个函数有两个参数,分别为resolve和reject
  • Promise有3中状态pending、fulfilled、rejected
  • resolve函数是将状态由pending改为fulfilled,reject函数是将状态由pending 改为rejected,且状态一旦变为fulfilled或者rejected就不能再更改状态了
  • then方法接收两个函数参数,成功执行第一个,失败执行第二个,且要将成功(resolve)、失败(reject)的参数传入相应的函数中
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class myPromise{
  constructor(execute){
    execute(this.resolve,this.reject)
  }
  status = PENDING;
  successParams = undefined;
  failParams = undefined;
  resolve = (value)=>{
    if(this.status !== PENDING) return;
    this.status = FULFILLED;
    this.successParams = value;
  }
  reject = (error)=>{
    if(this.status !== PENDING) return;
    this.status = REJECTED;
    this.failParams = error;
  }
  then = (successCallback,failCallback)=>{
    if(this.status === FULFILLED){
      successCallback(this.successParams)
    }
    if(this.status === REJECTED){
      failCallback(this.failParams)
    }
  }
}

如果Promise立即执行函数中有一个异步的方法,那么then函数没法立即执行,见下面:

let p = new myPromise((resolve,reject)=>{
  setTimeout(()=>{
    resolve('sucess');
  },2000);
})

解决方法:将then函数的两个方法存储起来,等resolve或者reject之后再执行

class myPromise{
  ...
  successCallback = undefined;
  failCallback = undefined;
  resolve = (value)=>{
    ...
    this.successCallback && this.successCallback(value);
  }
  reject = (error)=>{
    ...
    this.failCallback && this.failCallback(error)
  }
  then = (successCallback,failCallback)=>{
    ...
    if(this.status === PENDING){
      this.successCallback = successCallback;
      this.failCallback = failCallback;
    }
  }
}

Promise 还可以同时调用多个then方法,如:

p.then(data=>{
  console.log(1)
  console.log(data)
},error=>{
  console.log(error)
})

p.then(data=>{
  console.log(2)
  console.log(data)
},error=>{
  console.log(error)
})

思路:(如果Promise立即执行函数中是同步不需要改变,如果是异步需要改变)

将then中的两个函数用数组存储起来,等到resolve、reject后依次执行


class myPromise{
  ...
  successCallback = [];
  failCallback = [];
  resolve = (value)=>{
   ...
    //this.successCallback && this.successCallback(value);
    while(this.successCallback.length) this.successCallback.shift()(value)
  }
  reject = (error)=>{
    ...
    // this.failCallback && this.failCallback(error)
    while(this.failCallback.length) this.failCallback.shift()(error)
  }
  then = (successCallback,failCallback)=>{
    ...
    if(this.status === PENDING){
      this.successCallback.push(successCallback);
      this.failCallback.push(failCallback);
    }
  }
}

Promise链式调用

p.then(data=>{
  console.log(data)
  return 100
}).then(data1=>{
  console.log(111)
  console.log(data1)
})

同步思路:

  • then返回的要是一个Promise对象,这样才能继续调用then
  • 上一个then的返回值给下一个then使用
class myPromise{
	...
  then = (successCallback,failCallback)=>{
    let p2 = new myPromise((resolve)=>{
      if(this.status === FULFILLED){
        let x = successCallback(this.successParams);
        resolve(x)
      }
      if(this.status === REJECTED){
        failCallback(this.failParams)
      }
      if(this.status === PENDING){
        this.successCallback.push(successCallback);
        this.failCallback.push(failCallback);
      }
    })
    return p2;
  }
}

Promise then第一个函数返回有可能是普通参数,也有可能是Promise对象(同步)

function testPromise(){
  return new MyPromise((resolve,reject)=>{
    resolve(2)
  })
}
p.then(data=>{
  console.log(data)
  return testPromise()
}).then(data1=>{
  console.log(111)
  console.log(data1)
})

思路:

  • 如果返回的是普通参数,直接返回给下一个then使用
  • 如果返回的是一个Promise对象,将成功的参数返回给下一个then的第一个函数使用,失败的参数返回给第二个函数使用
class MyPromise{
  ...
  then = (successCallback,failCallback)=>{
    let p2 = new MyPromise((resolve,reject)=>{
      if(this.status === FULFILLED){
        let x = successCallback(this.successParams);
        promiseResolve(x,resolve,reject)
      }
	     ...
    })
    return p2;
  }
}

function promiseResolve(x,resolve,reject){
  if(x instanceof MyPromise){
    x.then(resolve,reject)
  }else{
    resolve(x)
  }
}

Promise then(第一个函数) 不能返回当前的这个Promise对象:

let p1 = p.then(data=>{
  console.log(data)
  return p1
})

思路:比对then返回的Promise和当前的promise对象,如果一样就抛错

class MyPromise{
  ...
  then = (successCallback,failCallback)=>{
    let p2 = new MyPromise((resolve,reject)=>{
      if(this.status === FULFILLED){
        setTimeout(()=>{
          let x = successCallback(this.successParams);
          promiseResolve(p2,x,resolve,reject)
        },0);
      }
      ...
    })
    return p2;
  }
}

function promiseResolve(p,x,resolve,reject){
  if(p === x){
    return reject(new TypeError('error'))
  }
...
}

遇到两个坑,1.必须加setTimeout,否则拿不到当前的Promise对象p2和then返回的当前Promise对象;2.在使用的时候,不能then去链式调用,这样两个Promise就不一样,没法比较了,见下面

错误的写法:
 p.then(data=>{
  console.log(data)
  return p1
}).then(data1=>{
  console.log(111)
},reason=>{
  console.log(reason)
})

正确的写法:
let p1 = p.then(data=>{
  console.log(data)
  return p1
})
p1.then(data1=>{
  console.log(111)
},reason=>{
  console.log(reason)
})

捕获Promise中的错误

思路:promise中的错误来源

  • Promise立即执行函数
  • then中的两个函数
class MyPromise{
  constructor(execute){
    try {
      execute(this.resolve,this.reject)
    } catch (error) {
      this.reject(error)
    }
  }
  ...
  resolve = (value)=>{
    ...
    while(this.successCallback.length) this.successCallback.shift()()
  }
  reject = (error)=>{
    ...
    while(this.failCallback.length) this.failCallback.shift()()
  }
  then = (successCallback,failCallback)=>{
    let p2 = new MyPromise((resolve,reject)=>{
      if(this.status === FULFILLED){
        setTimeout(()=>{
          try {
            let x = successCallback(this.successParams);
            promiseResolve(p2,x,resolve,reject)
          } catch (error) {
            reject(error)
          }
        },0);
      }
      if(this.status === REJECTED){
        setTimeout(()=>{
          try {
            let x = failCallback(this.failParams);
            promiseResolve(p2,x,resolve,reject)
          } catch (error) {
            reject(error)
          }
        },0);
      }
      if(this.status === PENDING){
        this.successCallback.push(()=>{
          setTimeout(()=>{
            try {
              let x = successCallback(this.successParams);
              promiseResolve(p2,x,resolve,reject)
            } catch (error) {
              reject(error)
            }
          },0);
        });
        this.failCallback.push(()=>{
          setTimeout(()=>{
            try {
              let x = failCallback(this.failParams);
              promiseResolve(p2,x,resolve,reject)
            } catch (error) {
              reject(error)
            }
          },0);
        });
      }
    })
    return p2;
  }
}

注意:异步方法是在resolve/reject执行后,才执行下一个相应的then函数,

Promise还有一种调用方法.then中是空的

p.then().then().then(value=>console.log(value))

思路:在then中没有函数的时候,补齐函数(下面是源码)

const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class MyPromise{
  constructor(execute){
    try {
      execute(this.resolve,this.reject)
    } catch (error) {
      this.reject(error)
    }
  }
  status = PENDING;
  successParams = undefined;
  failParams = undefined;
  successCallback = [];
  failCallback = [];
  resolve = (value)=>{
    if(this.status !== PENDING) return;
    this.status = FULFILLED;
    this.successParams = value;
    while(this.successCallback.length) this.successCallback.shift()()
  }
  reject = (error)=>{
    if(this.status !== PENDING) return;
    this.status = REJECTED;
    this.failParams = error;
    while(this.failCallback.length) this.failCallback.shift()()
  }
  then = (successCallback,failCallback)=>{
    successCallback = successCallback ? successCallback : value => value;
    failCallback = failCallback ? failCallback : value => value;
    let p2 = new MyPromise((resolve,reject)=>{
      if(this.status === FULFILLED){
        setTimeout(()=>{
          try {
            let x = successCallback(this.successParams);
            promiseResolve(p2,x,resolve,reject)
          } catch (error) {
            reject(error)
          }
        },0);
      }
      if(this.status === REJECTED){
        setTimeout(()=>{
          try {
            let x = failCallback(this.failParams);
            promiseResolve(p2,x,resolve,reject)
          } catch (error) {
            reject(error)
          }
        },0);
      }
      if(this.status === PENDING){
        this.successCallback.push(()=>{
          setTimeout(()=>{
            try {
              let x = successCallback(this.successParams);
              promiseResolve(p2,x,resolve,reject)
            } catch (error) {
              reject(error)
            }
          },0);
        });
        this.failCallback.push(()=>{
          setTimeout(()=>{
            try {
              let x = failCallback(this.failParams);
              promiseResolve(p2,x,resolve,reject)
            } catch (error) {
              reject(error)
            }
          },0);
        });
      }
    })
    return p2;
  }
}

function promiseResolve(p,x,resolve,reject){
  if(p === x){
    return reject(new TypeError('error'))
  }
  if(x instanceof MyPromise){
    x.then(resolve,reject)
  }else{
    resolve(x)
  }
}

如果有错误或者不严谨的地方,请务必给予指正,十分感谢。