JavaScript简单实现一个Promise

91 阅读4分钟

一、实现Promise的基本功能

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

// new promise时传入一个函数fn = (resove,reject) => {}
class MyPromise {
  constructor(fn) {
    this.state = PENDING   //用state保存Promise的三种装填
    this.value = undefined //用value保存Promise传递的值

    let resolve = (value) => { // 调用resolve 修改状态为fulfilled
      if(this.state == PENDING) {
        this.state = FULFILLED
        this.value = value
      }
    }
    let reject = (error) => { // 调用reject 修改状态为rejected
      if(this.state == PENDING) {
        this.state = REJECTED
        this.value = error 
      }
    }

    fn(resolve, reject) // 调用传入的函数  
  }
  then(onFulFilled, onRejected) {
    if(this.state == FULFILLED) { // 状态为fulfilled 执行成功的回调
      onFulFilled(this.value)
    }
    if(this.state == REJECTED) { // 状态为rejected 执行失败的回调
      onRejected(this.value)
    }
  }
}


console.log('p0');
let p1 = new MyPromise((resolve,reject) => {
  resolve('p1')
})
p1.then(res => {
  console.log(res);
})
console.log('p2');
// 输出结果 p0 p1 p2
// 但因为promise的异步的 正确的输出应该是p0 p2 p1

二、添加异常捕获

try {
  fn(resolve, reject)
} catch(err) {
  reject(err)
}

let p1 = new MyPromise((resolve,reject) => {
  throw new Error('custom error')
})
p1.then(res => {
  console.log(res);
},err => {
  console.log(err); // custom error
})

三、实现Promise的异步

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

class MyPromise {
  constructor(fn) {
    this.state = PENDING
    this.value = undefined

    this.onFulCallBack = [] // 添加数组用来保存PENDING的回调函数 
    this.onRejCallBack = []

    let resolve = (value) => {
      setTimeout(() => {    // 实现Promise的异步
        if(this.state == PENDING) {
          this.state = FULFILLED
          this.value = value
          this.onFulCallBack.forEach(cb => cb()) // 等待异步结束后执行数组里面的回调函数
        }
      })
    }
    let reject = (error) => {
      setTimeout(() => {    // 实现Promise的异步
        if(this.state == PENDING) {
          this.state = REJECTED
          this.value = error
          this.onRejCallBack.forEach(cb => cb()) // 等待异步结束后执行数组里面的回调函数
        }
      })
    }
    try {
      fn(resolve, reject) 
    } catch(err) {
      reject(err)
    }
  }
  then(onFulFilled, onRejected) {
    if(this.state == FULFILLED) {
      onFulFilled(this.value)
    }
    if(this.state == REJECTED) {
      onRejected(this.value)
    }
    if(this.state == PENDING) { // 状态为PENDING时 将回调函数放到数组里
      this.onFulCallBack.push(() => onFulFilled(this.value))
      this.onRejCallBack.push(() => onRejected(this.value))
    }
  }
}


console.log('p0');
let p1 = new MyPromise((resolve,reject) => {
  resolve('p1')
  // setTimeout(() => {
  //   resolve('p1')
  // },1000)
})
p1.then(res => {
  console.log(res);
},err => {
  console.log(err);
})
console.log('p2');
// 输出结果 p0 p2 p1

四、实现then中值的穿透

then(onFulFilled, onRejected) {
    onFulFilled = typeof onFulFilled == 'function' ? onFulFilled : value => value
    onRejected = typeof onRejected == 'function' ? onRejected : err => {throw err}
    if(this.state == FULFILLED) {
      onFulFilled(this.value)
    }
    if(this.state == REJECTED) {
      onRejected(this.value)
    }
    if(this.state == PENDING) { 
      this.onFulCallBack.push(() => onFulFilled(this.value))
      this.onRejCallBack.push(() => onRejected(this.value))
    }
  }

五、实现then的链式调用

then(onFulFilled, onRejected) {
    onFulFilled = typeof onFulFilled == 'function' ? onFulFilled : value => value
    onRejected = typeof onRejected == 'function' ? onRejected : err => {throw err}
    let promise = new MyPromise((resolve,reject) => {
      const resolvePromise = promiseRes => {
        try {
          var x = onFulFilled(promiseRes)
          if(x instanceof MyPromise) {
            x.then(resolve, reject)
          }
          resolve(x)
        } catch(err) {
          reject(err)
        }
      }
      const rejectPromise = promiseRes => {
        try {
          var x = onRejected(promiseRes)
          if(x instanceof MyPromise) {
            x.then(resolve, reject)
          }
          reject(x)
        } catch(err) {
          reject(err)
        }
      }
      if(this.state == FULFILLED) {
        resolvePromise(this.value)
      }
      if(this.state == REJECTED) {
        rejectPromise(this.value)
      }
      if(this.state == PENDING) { 
        this.onFulCallBack.push(() => resolvePromise(this.value))
        this.onRejCallBack.push(() => rejectPromise(this.value))
      }
    })
    return promise
  }
  
  let p1 = new MyPromise((resolve,reject) => {
    resolve(123)
  })
  p1.then(res => {
    return res
  }).then(res => {
    console.log(res); // 123
  })

六、catch实现

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

let p = new MyPromise((resolve,reject) => {
  reject('123')
})
p.catch((err) => {
  console.log(err); // 123
})

七、finally实现

finally(callback) {
  let P = this.constructor
  return this.then(
    value  => P.resolve(callback()).then(() => value),
    reason => P.resolve(callback()).then(() => { throw reason })
  );
};

let p = new MyPromise((resolve,reject) => {
  resolve('123')
})
p.finally(() => {
  console.log('finally'); // finally
})

八、Promise.all实现

  static all(promises) {
    return new MyPromise((resolve,reject) => {
      if(!Array.isArray(promises)) {
        throw new Error('argument must be a Array')
      }
      let counter = 0
      let num = promises.length
      let result = []
      for(let i = 0; i < num; i++) {
        promises[i].then(value => {
          counter++
          result[i] = value
          if(counter == num) {
            return resolve(result)
          }
        }, err => {
          return reject(err)
        })
      }
    })
  }
  
const p1 = new MyPromise((resolve) => {
  setTimeout(() => {
    resolve('a')
  },1000)
})
const p2 = new MyPromise((resolve) => {
  setTimeout(() => {
    resolve('b')
  },3000)
})
const p3 = new MyPromise((resolve) => {
  setTimeout(() => {
    resolve('c')
  },2000)
})
MyPromise.all([p1,p2,p3]).then(res => {
  console.log(res);  // [ 'a', 'b', 'c' ]
})

九、Promise.resolve实现

static resolve(v) {
    // 1.返回是一个Promise实例
    if(v instanceof MyPromise) {
      return v
    }
    // 2.参数是一个对象 包含then方法
    if(typeof v === 'object' && typeof v.then === 'function') {
      return new MyPromise((res,rej) => {
        v.then(res, rej)
      })
    }
    // 3.没有参数
    if(!v) {
      return new MyPromise(res => {
        res()
      })
    }
    // 4.参数是原始值
    return new MyPromise(res => {
      res(v)
    })
  }

十、Promise.reject实现

  static reject(v) {
    return new MyPromise((res,rej) => {
      rej(v)
    })
  }

十一、Promise.race实现

  static race(promises) {
    return new MyPromise((resolve, reject) => {
      if(!Array.isArray(promises)) {
        throw new Error('argument must be a Array')
      }
      for(let i = 0; i < promises.length; i++) {
        promises[i].then(resolve, reject)
      }
    })
  }
  
const p1 = new MyPromise((resolve) => {
  setTimeout(() => {
    resolve('a')
  },1000)
})
const p2 = new MyPromise((resolve) => {
  setTimeout(() => {
    resolve('b')
  },3000)
})
const p3 = new MyPromise((resolve) => {
  setTimeout(() => {
    resolve('c')
  },2000)
})
MyPromise.race([p1,p2,p3]).then(res => {
  console.log(res);  // a
})

十二、完整代码

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

class MyPromise {
  constructor(fn) {
    this.state = PENDING
    this.value = undefined

    this.onFulCallBack = [] 
    this.onRejCallBack = []

    let resolve = (value) => {
      if(value instanceof MyPromise) {
        return value.then(resolve, reject)
      }
      setTimeout(() => {
        if(this.state == PENDING) {
          this.state = FULFILLED
          this.value = value
          this.onFulCallBack.forEach(cb => cb())
        }
      })
    }
    let reject = (error) => {
      setTimeout(() => {
        if(this.state == PENDING) {
          this.state = REJECTED
          this.value = error
          this.onRejCallBack.forEach(cb => cb())
        }
      })
    }
    try {
      fn(resolve, reject) 
    } catch(err) {
      reject(err)
    }
  }

  then(onFulFilled, onRejected) {
    onFulFilled = typeof onFulFilled == 'function' ? onFulFilled : value => value
    onRejected = typeof onRejected == 'function' ? onRejected : err => {throw err}
    let promise = new MyPromise((resolve,reject) => {
      const resolvePromise = promiseRes => {
        try {
          var x = onFulFilled(promiseRes)
          if(x instanceof MyPromise) {
            x.then(resolve, reject)
          }
          resolve(x)
        } catch(err) {
          reject(err)
        }
      }
      const rejectPromise = promiseRes => {
        try {
          var x = onRejected(promiseRes)
          if(x instanceof MyPromise) {
            x.then(resolve, reject)
          }
          reject(x)
        } catch(err) {
          reject(err)
        }
      }
      if(this.state == FULFILLED) {
        resolvePromise(this.value)
      }
      if(this.state == REJECTED) {
        rejectPromise(this.value)
      }
      if(this.state == PENDING) { 
        this.onFulCallBack.push(() => resolvePromise(this.value))
        this.onRejCallBack.push(() => rejectPromise(this.value))
      }
    })
    return promise
  }

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

  finally(callback) {
    let P = this.constructor
    return this.then(
      value  => P.resolve(callback()).then(() => value),
      reason => P.resolve(callback()).then(() => { throw reason })
    )
  }

  static all(promises) {
    return new MyPromise((resolve,reject) => {
      if(!Array.isArray(promises)) {
        throw new Error('argument must be a Array')
      }
      let counter = 0
      let num = promises.length
      let result = []
      for(let i = 0; i < num; i++) {
        promises[i].then(value => {
          counter++
          result[i] = value
          if(counter == num) {
            return resolve(result)
          }
        }, err => {
          return reject(err)
        })
      }
    })
  }
  
  static resolve(v) {
    // 1.返回是一个Promise实例
    if(v instanceof MyPromise) {
      return v
    }
    // 2.参数是一个对象 包含then方法
    if(typeof v === 'object' && typeof v.then === 'function') {
      return new MyPromise((res,rej) => {
        v.then(res, rej)
      })
    }
    // 3.没有参数
    if(!v) {
      return new MyPromise(res => {
        res()
      })
    }
    // 4.参数是原始值
    return new MyPromise(res => {
      res(v)
    })
  }

  static reject(v) {
    return new MyPromise((res,rej) => {
      rej(v)
    })
  }

  static race(promises) {
    return new MyPromise((resolve, reject) => {
      if(!Array.isArray(promises)) {
        throw new Error('argument must be a Array')
      }
      for(let i = 0; i < promises.length; i++) {
        promises[i].then(resolve, reject)
      }
    })
  }
}