深入简出 Promise

221 阅读3分钟

Promise API 详细了解

  1. Promise在执行这个类的时候,需要传递一个执行器进去,这个执行器会立即执行,执行器这个回调函数,还有两个参数,这里两个参数分别是resolve,reject,调用resolve,reject就是修改promise的状态
  2. promise 中有三种状态:pending fulfilled,rejected,promise pending => fulfuiiled pending => rejected 一旦状态改变就不可更改
  3. resolve跟reject用来更改状态
new Promise(function (resolve, reject) {
  resolve('成功')
  reject('失败')
})

Promise.all

Promise.all是静态方法,接受一个数组,数组中可以是任何数据类型,如果是一个Promise对象,调用.then方法则会等待异步的执行完毕,then中的callback执行时机取决于数组列表中的promise最长消耗的时间

const timeoutAsync = timer => {
  return new Promise((resolve, reject) => {
      setTimeout(() => {
          resolve(timer)
      }, timer)
  })
}
const p1 = timeoutAsync(1)
const p2 = timeoutAsync(2)
Promise.all([p1, p2]).then(rs => {
  console.log(rs)
  console.log(rs instanceof Array)  // true
  }, err => {
  // 此处err是第一个发生reject的promise返回结果,参数类型取决于reject的结果
  console.log(err)
})

Promise.race

静态方法

const timeoutAsync = timer => {
  return new Promise((resolve, reject) => {
      setTimeout(() => {
          resolve(timer)
      }, timer)
  })
}
const p1 = timeoutAsync(1)
const p2 = timeoutAsync(2)
Promise.race([p1, p2]).then(rs => {
  console.log(rs)   // 1
}, err => {
  console.log(err)
})

Promise.prototype.then

// then方法接受两个参数,一个是成功的回调,一个失败的回调
const p2 = timeoutAsync(2).then(rs => {
  console.log(rs)
}, err => {
    
})
// 支持多次调用
p2.then()
p2.then()
p2.then(rs => rs1).then(rs1 => rs2)
// 支持链式调用,第二个then方法回调函数的参数是上一个回调函数的返回值
// 如果是普通值,直接返回,如果是promise,则等待异步操作调用结束,返回resolve,reject传递进来的值

实现一个Promise

// promise的三种状态,更改之后不可变
const PENDING = 'pending'
const FULFILLED = 'fullfiled'
const REJECTED = 'rejected'
class MyPromise {
  status = PENDING
  // then方法的参数回调函数调用返回的值
  value = undefined
  reason = undefined
  successCallback = []
  failCallback = []
  constructor(executor) {
    // 捕获执行器的错误
    try {
      // 立即执行,传入resolve,reject
      executor(this.resolve, this.reject)
    } catch (e) {
      this.reject(e)
    }
    
  }
  resolve = value => {
    // 状态不是PENDING的时候阻止向下执行
    if (this.status !== PENDING) {
      return
    }
    this.value = value
    this.status = FULFILLED
    
    while(this.successCallback.length) {
      this.successCallback.shift()()
    }
  }
  reject = reason => {
    // 状态不是PENDING的时候阻止向下执行
    if (this.status !== PENDING) {
      return
    }
    this.reason = reason
    this.status = REJECTED
    while(this.failCallback.length) {
      this.failCallback.shift()()
    }
  }
  // 状态为FULFILLED时候调用成功回调,状态为REJECTED的时候调用failCallback回调
  
  then = (successCallback, failCallback) => {
    successCallback = successCallback ? successCallback : value => value
    failCallback = failCallback ? failCallback : reason => reason
    // 返回的promise支持链式调用,内部executor是同步执行,所以可以把then方法的逻辑放入执行器中
    const thenPromise = new MyPromise((resolve, reject) => {
      if (this.status ===  FULFILLED) {
        // 使用setTimeout为了拿到thenPromise
        setTimeout(() => {
          // 捕获成功回调的错误
          try {
            let r = successCallback(this.value)
            // 判断返回值是普通值还是promise对象,
            resolvePromise(thenPromise, r, resolve, reject)
          } catch (e) {
            reject(e)
          }
        }, 0)
      } else if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            let r = failCallback(this.reason)
            // 判断返回值是普通值还是promise对象,
            resolvePromise(thenPromise, r, resolve, reject)
          } catch (e) {
            reject(e)
          }
        }, 0)
      // 如果executor中没有异步状态,那么执行到then方法的时候状态不是PEDING,如果executor里边有异步操作,则需要判断PENDING的情况
      // 所以需要讲then方法中传递进来的回调函数保存起来,等到resolve,reject的时候调用对应的回调函数
      } else {
        this.successCallback.push(() => {
          setTimeout(() => {
            try {
              let r = successCallback(this.value)
              // 判断返回值是普通值还是promise对象,
              resolvePromise(thenPromise, r, resolve, reject)
            } catch (e) {
              reject(e)
            }
          }, 0)
        })
        this.failCallback.push(() => {
          setTimeout(() => {
            try {
              let r = failCallback(this.reason)
              // 判断返回值是普通值还是promise对象,
              resolvePromise(thenPromise, r, resolve, reject)
            } catch (e) {
              reject(e)
            }
          }, 0)
        })
      }
    })
    function resolvePromise(thenPromise, r, resolve, reject) {
      // 判断如果then方法回调函数返回的promise是本身,返回一个循环引用错误
      if (thenPromise === r) {
        reject(new TypeError('cycle call'))
        return;
      }
      // 如果是promise对象,则处理then方法的逻辑
      
      if (r instanceof MyPromise) {
        
        r.then(resolve, reject)
      } else {
        // 如果是普通值,直接resolve
        resolve(r)
      }
    }
    
    // then方法返回一个promise实现链式调用
    return thenPromise;
  }
  static all = array => {
    const result = []
    return new MyPromise((resolve, reject) => {
      let index = 0
      function addData (key, value) {
        result[key] = value
        index++
        if (index === array.length) {
          resolve(result)
        }
      }
      for (let i=0;i<array.length;i++) {
        const current = array[i]
        if (current instanceof MyPromise) {
          current.then(value => addData(i, value), reason => addData(i, reason))
        } else {
          addData(i, current)
        }
      }
      
    })
  }
  finally = callback => {
    return this.then(value => {
      return Promise.resolve(callback()).then(() => value)
    }, reason => {
      return Promise.resolve(callback()).then(() => {throw reason})
    })
  }
  catch = failCallback => {
    return this.then(undefined, failCallback)
  }
  static resolve = value => {
    if (value instanceof MyPromise) return value
    return new MyPromise(resolve => resolve(value))
  }
  static reject = value => {
    if (value instanceof MyPromise) return value
    return new MyPromise(undefined, reject => reject(value))
  }
}
module.exports = MyPromise