promise

181 阅读5分钟

今天本来想学习一下promise并总结一下,但是发现了 juejin.cn/post/684490… 写的很好,里面不止讲述了promise原理还有 async/await实现,Generator实现 学习了一波,本篇只相当于个人笔记。

Promise/A+规范

  1. 术语
  • promise是一个包含了兼容promise 规范then 方法的对象或函数
  • thenable是一个包含了then方法的对象或函数
  • value是任何javascript
  • exception是由throw表达式刨出来的值
  • reason是用于描述promise被拒绝的原因的值
  1. 要求

promise必须是在pending,fulfilled,rejected状态之一,当promise转变成fulfilled,rejected状态时,promise的状态就不能改变了。

  • promise.then(onFulfilled, onRejected),promise.then要接受2个参数,但是这个2个参数都是可选的,如果onFulfilled, onRejected其中不是函数就忽略。
  • onFulfilled可以理解为一个成功的函数他必须在promise fulfilled后调用,value是第一个参数
  • onRejected可以理解为一个失败的函数他必须在promise rejected后调用,reason是第一个参数
  • then的返回值必须是一个promise

promise小例子

 const promise1 = new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('成功函数')
    }, 1000)
})
promise1.then((success) => {
  console.log('-----------success---------------------', success)
}, (err) => {
  console.log('--------------err------------------', err)
})

// -----------success--------------------- 成功函数

promisethen方法会搜集new Promise里面的resolve, reject函数,当executor()在执行异步任务的时候,触发resolve/reject从相应的队列中取出回调依次执行

收集依赖 -> 触发通知 -> 取出依赖执行

then收集依赖 -> 异步触发resolve -> resolve执行依赖

手写一个简答的promise

 class MyPromise {
  constructor(executor) {
    this.resolveGroup = []; // 存放then搜集的resolve函数
    this.rejectGroup = [];  //存放then搜集的reject函数

    let currentResolve = (val) => {
      while (this.resolveGroup.length) {
        const cb = this.resolveGroup.shift();
        cb(val)
      }
    }

    let currentReject = (val) => {
      while (this.rejectGroup.length) {
        const cb = this.rejectGroup.shift();
        cb(val)
      }
    }

    executor(currentResolve, currentReject)
  }
  // 搜集函数
  then(resolveFun, rejectFun) {
    this.resolveGroup.push(resolveFun);
    this.rejectGroup.push(rejectFun);
  }
}

// 测试MyPromise
const promise1 = new MyPromise((resolve, reject) => {
    setTimeout(() => {
      resolve('成功函数')
    }, 1000)
})

promise1.then((success) => {
  console.log('-----------success---------------------', success)
}, (err) => {
  console.log('--------------err------------------', err)
})

promise加入status

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

class MyPromise {
  constructor(executor) {
    this.resolveGroup = []; // 存放then搜集的resolve函数
    this.rejectGroup = [];  //存放then搜集的reject函数
    this.status = PENDING;  // 在promise 中状态从pending开始,一旦变化,就不能再次更改
    let currentResolve = (val) => {
      if (this.status !== PENDING) return;
      this.status = FULFILLED;
      while (this.resolveGroup.length) {
        const cb = this.resolveGroup.shift();
        cb(val)
      }
    }

    let currentReject = (val) => {
      if (this.status !== PENDING) return;
      this.status = REJECTED;
      while (this.rejectGroup.length) {
        const cb = this.rejectGroup.shift();
        cb(val)
      }
    }
    executor(currentResolve, currentReject)
  }
  // 搜集函数
  then(resolveFun, rejectFun) {
    this.resolveGroup.push(resolveFun);
    this.rejectGroup.push(rejectFun);
  }
}

const promise1 = new MyPromise((resolve, reject) => {
    setTimeout(() => {
      resolve('成功函数')
    }, 1000)
})

promise1.then((success) => {
  console.log('-----------success---------------------', success)
}, (err) => {
  console.log('--------------err------------------', err)
})

promise.then 的链式调用实现

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

class MyPromise {
  constructor(executor) {
    this.resolveGroup = []; // 存放then搜集的resolve函数
    this.rejectGroup = [];  //存放then搜集的reject函数
    this.status = PENDING;  // 在promise 中状态从pending开始,一旦变化,就不能再次更改
    let currentResolve = (val) => {
      if (this.status !== PENDING) return;
      this.status = FULFILLED;
      while (this.resolveGroup.length) {
        const cb = this.resolveGroup.shift();
        cb(val)
      }
    }

    let currentReject = (val) => {
      if (this.status !== PENDING) return;
      this.status = REJECTED;
      while (this.rejectGroup.length) {
        const cb = this.rejectGroup.shift();
        cb(val)
      }
    }
    executor(currentResolve, currentReject)
  }
  // 搜集函数
  then(resolveFun, rejectFun) {
    // then 为了实现链式调用,要返回一个新的promise
    return new MyPromise((resolve, reject) => {
      // 把resolveFun重新包装一下,并且要判断一下resolveFun的返回着,如果返回值
      const fulfilledFn = value => {
        try {
          const x = resolveFun(value);
          x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
        } catch (e) {
          reject(e)
        }
      }
      // 搜集当前  resolveFun 返回的新的函数
      this.resolveGroup.push(fulfilledFn);
      const rejectedFn = value => {
        try {
          const x = rejectFun(value);
          x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
        } catch (e) {
          reject(e)
        }
      }

      this.resolveGroup.push(rejectedFn);
    })
    // this.resolveGroup.push(resolveFun);
    // this.rejectGroup.push(rejectFun);
  }
}
const promise1 = new MyPromise((resolve, reject) => {
    setTimeout(() => {
      resolve(1)
    }, 1000)
})

promise1.then((res) => {
  console.log('--------------res2------------------', res)
  return 2
}).then((res) => {
  console.log('--------------res3------------------', res)
  return 3
}).then((res) => {
  console.log('-------------res4-------------------', res)
})

值穿透和状态变更

  1. 值穿透:then接收2个参数作回调,但是resolve, reject这个2个参数是可选的,并且,当传入的参数不是函数时,要忽略,所以要对参数的类型做判断。
  2. 状态变更:在promise中时长会有状态是fulfilledrejected时,resolve()reject()then之前就已经执行。
// 官方例子 Promise.resolve().then() resolve()方法在then之前执行
const promise1 = Promise.resolve(123);
promise1.then(function(value) {
  console.log(value);
  // expected output: 123
});

实现值穿透和状态变更

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

class MyPromise {
  constructor(executor) {
    this.resolveGroup = []; // 存放then搜集的resolve函数
    this.rejectGroup = [];  //存放then搜集的reject函数
    this.status = PENDING;  // 在promise 中状态从pending开始,一旦变化,就不能再次更改
    this.value = undefined;
    let currentResolve = (val) => {
      if (this.status !== PENDING) return;
      this.status = FULFILLED;
      this.value = val;
      while (this.resolveGroup.length) {
        const cb = this.resolveGroup.shift();
        cb(val)
      }
    }

    let currentReject = (val) => {
      if (this.status !== PENDING) return;
      this.status = REJECTED;
      this.value = val;
      while (this.rejectGroup.length) {
        const cb = this.rejectGroup.shift();
        cb(val)
      }
    }
    executor(currentResolve, currentReject)
  }
  // 搜集函数
  then(resolveFun, rejectFun) {
    // 值穿透,参数判断
    typeof resolveFun === 'function' ?  null : resolveFun = value => value
    typeof rejectFun === 'function' ? null : rejectFun = error => error
    // then 为了实现链式调用,要返回一个新的promise
    return new MyPromise((resolve, reject) => {
      // 把resolveFun重新包装一下,并且要判断一下resolveFun的返回着,如果返回值
      const fulfilledFn = value => {
        try {
          const x = resolveFun(value);
          x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
        } catch (e) {
          reject(e)
        }
      }

      const rejectedFn = value => {
        try {
          const x = rejectFun(value);
          x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
        } catch (e) {
          reject(e)
        }
      }

      // 搜集当前  resolveFun 返回的新的函数
      // 当前状态不是pending的时候,函数直接执行,不再搜集
      if (this.status === PENDING) {
        this.resolveGroup.push(fulfilledFn);
        this.rejectGroup.push(rejectedFn);
      } else if (this.status === FULFILLED) {
        fulfilledFn(this.value)
      } else {
        rejectedFn(this.value)
      }
    })
    // this.resolveGroup.push(resolveFun);
    // this.rejectGroup.push(rejectFun);
  }
}
const promise1 = new MyPromise((resolve, reject) => {
    setTimeout(() => {
      resolve(1)
    }, 1000)
})
promise1.then(2, (err) => {
  console.log('------------err--------------------', err)
})
// 没有任何输出

兼容同步任务

Promise的默认实现是放进了微任务队列,我们的实现(包括大多数Promise手动实现和polyfill的转化)都是使用setTimeout放入了宏任务队列(当然我们也可以用MutationObserver模拟微任务)

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

class MyPromise {
  constructor(executor) {
    this.resolveGroup = []; // 存放then搜集的resolve函数
    this.rejectGroup = [];  //存放then搜集的reject函数
    this.status = PENDING;  // 在promise 中状态从pending开始,一旦变化,就不能再次更改
    this.value = undefined;
    let currentResolve = (val) => {
      const fun = () => {
        if (this.status !== PENDING) return;
        this.status = FULFILLED;
        this.value = val;
        while (this.resolveGroup.length) {
          const cb = this.resolveGroup.shift();
          cb(val)
        }
      }
      // 为了兼容同步任务,特定设置的setTimeout
      setTimeout(fun)
    }

    let currentReject = (val) => {
      const fun = () => {
        if (this.status !== PENDING) return;
        this.status = REJECTED;
        this.value = val;
        while (this.rejectGroup.length) {
          const cb = this.rejectGroup.shift();
          cb(val)
        }
      }
      setTimeout(fun)
    }
    executor(currentResolve, currentReject)
  }
  // 搜集函数
  then(resolveFun, rejectFun) {
    // 值穿透,参数判断
    typeof resolveFun === 'function' ?  null : resolveFun = value => value
    typeof rejectFun === 'function' ? null : rejectFun = error => error
    // then 为了实现链式调用,要返回一个新的promise
    return new MyPromise((resolve, reject) => {
      // 把resolveFun重新包装一下,并且要判断一下resolveFun的返回着,如果返回值
      const fulfilledFn = value => {
        try {
          const x = resolveFun(value);
          x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
        } catch (e) {
          reject(e)
        }
      }

      const rejectedFn = value => {
        try {
          const x = rejectFun(value);
          x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
        } catch (e) {
          reject(e)
        }
      }

      // 搜集当前  resolveFun 返回的新的函数
      // 当前状态不是pending的时候,函数直接执行,不再搜集
      if (this.status === PENDING) {
        this.resolveGroup.push(fulfilledFn);
        this.rejectGroup.push(rejectedFn);
      } else if (this.status === FULFILLED) {
        fulfilledFn(this.value)
      } else {
        rejectedFn(this.value)
      }
    })
    // this.resolveGroup.push(resolveFun);
    // this.rejectGroup.push(rejectFun);
  }
}

更好理解Promise / async / Generator 实现&原理请移步

写代码像蔡徐坤:Promise / async / Generator 实现&原理大解析(附源码)| 9k字