使用ES6中Class实现手写Promise

Promise出现的原因

promise出现的原因,说白了也就是promise解决了什么问题,这里我就简单说点吧: Promise 是异步编程的一种解决方案,比传统的解决方案回调函数和事件更合理和更强大,Promise的出现主要解决以下两个问题:

  • 回调地狱: 某个异步操作需要等待之前的操作完成在继续执行, 当这样的需求多了以后, 使的代码进入无尽的嵌套,可读性降低不好维护。
  • 异步和同步之间的联系问题:当一个同步操作需要等待多个异步操作的结果, 这样会使得代码的逻辑变得相对来说比较复杂。

myPromise的实现要点

  • Promise 就是一个类,实际上就是ES6提供的一个新的构造函数,
  • 通过new创建实例,接收一个函数作为参数,并且该函数中的代码默认是同步代码,会立即执行
  • Promise 有三种状态,成功resolved,失败rejected,等待pedding
  • Promise 状态一旦发生改变,就不能在改变,状态不可逆 用户可自定义成功的数据及失败的原因
  • Promise 实例拥有一个then方法。接受两个参数,一个成功回调,一个失败回调
  • executor执行器在执行过程中,可能会抛出异常 throw new Error(),需要 try catch 捕获
  • 当执行器中的是异步代码时(如定时器执行resolve),不是立即执行 状态不会变更,此时then方法中状态仍然是pending
  • 一个 promise 实例可以被 then 多次,分别创建一个队列用来存放成功和失败回调事件
  • 定时器执行时,判断状态为 pending,非立即执行,而是先存放 成功/失败 回调事件
  • 等待状态变为成功或失败时遍历队列依次执行对应的onfulfilled和onrejected,并且有执行顺序
  • Promise 实现链式调用,返回的并不是this,而是一个新的promise实例, 因为原有的promise状态一旦发生改变,就不能再改变,否则不符合规范
  • Promise 成功和失败的回调的返回值,可以传递给下一次的的then
    • 返回的是普通值:不论then是成功还是失败。只要是普通值就传递到下一次then的成功中。(普通值包括:非错误非promise,包括对象)
    • 报错或异常:一定会走到下一次then的失败中。如果离自己最近的then没有错误处理,会向下找
    • 特别注意: return new Error()返回的是错误对象,属于普通值走下一次then的成功,而throw new Error() 是抛出异常,需要try catch 会走下一次的失败
    • 返回的是promise:会采用promise的状态,决定下一次then是成功还是失败,此处会有递归判断
    • 总结: 如果返回一个普通值,除了promise ,就传递给下一个then的成功,如果返回一个失败的promise或者抛出异常,会走下一个then的失败。
  • Promise 值的穿透,当一个promise连续then 多次,并且then中没有返回任何值时,此时data会穿透至最后一个then中
    • 执行onfulfilled时,先判断是不是一个function,如果是就直接执行,反之就包一层函数
    • 执行onrejected时,先判断是不是一个function,如果是就直接执行,反之就抛出失败异常
  • 既然promise是为了解决异步回调函数嵌套问题,那么可以通过promise的延迟对象来减少一层嵌套关系
  • promiseA+ 规范测试
  • 聊点规范以外的东东吧~~catch, finally,resolve,reject,all,race,就这么多

myPromise的实现

下面就来实现以上要点

myPromise — 实现简单的同步 myPromise.js

// 要点 3: 有三种状态, 相当于是常量,可以放在外面
const RESOLVED = 'RESOLVED'
const REJECTED = 'REJECTED'
const PENDING = 'PENDING'
// 要点 1: Promise 就是一个类
class Promise {
  // 要点 2: 接收一个函数executor作为参数,立即执行
  constructor(executor) {
    this.status = PENDING
    this.value = undefined // 要点 5: 用户可自定义 成功的数据
    this.reason = undefined // 要点 5: 用户可自定义 失败的原因
    let resolve = (value) => {
      // 要点 4: 状态不可逆, 只有PENDING时,才可以改变状态
      if (this.status === PENDING) {
        this.value = value // 成功的数据
        this.status = RESOLVED // 状态置为 RESOLVED
      }
    }
    let reject = (reason) => {
      // 要点 4: 状态不可逆, 只有PENDING时,才可以改变状态
      if (this.status === PENDING) {
        this.reason = reason // 失败的原因
        this.status = REJECTED // 状态置为 REJECTED
      }
    }

    // 要点 7: 错误处理,抛出异常 throw new Error()
    try {
      executor(resolve, reject) // 立即执行
    } catch (e) { // 抛出异常 直接失败
      reject(e)
    }
  }
  // 要点 6: 拥有一个then方法(实例上的方法)。接受两个参数回调函数
  then(onfulfilled, onrejected) {
    if (this.status === RESOLVED) {
      onfulfilled(this.value)
    }
    if (this.status === REJECTED) {
      onrejected(this.reason)
    }
  }
}

// Commonjs规范导出模块
module.exports = Promise

test.js 简单的同步操作验证

// 使用自己的promise,注释该行代码,就是原生promise
let Promise = require('./myPromise')

let p = new Promise((resolve, reject) => {
  resolve('成功')
  // throw new Error('失败了')
  // reject('失败')
})

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

myPromise — 增加异步功能

在实现了简单的同步操作后,再来看看异步代码的执行,还是使用上面 test 中的案例,简单的改造一下,写一个定时器模拟异步环境,test.js:增加异步功能。

let p = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('成功')
  }, 1000)
})

p.then((data) => {
  console.log(data, 1)
}, (err) => {
  console.log(err)
})
// 一个实例可以then多次,执行结果会是一样的,因为状态已经固定
p.then((data) => {
  console.log(data, 2)
}, (err) => {
  console.log(err)
})

myPromise.js

const RESOLVED = 'RESOLVED'
const REJECTED = 'REJECTED'
const PENDING = 'PENDING'
class Promise {
  constructor(executor) {
    this.status = PENDING
    this.value = undefined
    this.reason = undefined
    // 要点 9: 分别创建一个`队列用来存放成功和失败回调事件
    this.onfulfilledCallbacks = []
    this.onrejectedCallbacks = []
    let resolve = (value) => {
      if (this.status === PENDING) {
        this.value = value
        this.status = RESOLVED
        this.onfulfilledCallbacks.forEach(fn => fn()) // 要点 11: 状态变为成功时遍历队列依次执行
      }
    }
    let reject = (reason) => {
      if (this.status === PENDING) {
        this.reason = reason
        this.status = REJECTED
        this.onrejectedCallbacks.forEach(fn => fn()) // 要点 11: 状态变为失败时遍历队列依次执行
      }
    }

    try {
      executor(resolve, reject)
    } catch (e) {
      reject(e)
    }
  }
  then(onfulfilled, onrejected) {
    if (this.status === RESOLVED) {
      onfulfilled(this.value)
    }
    if (this.status === REJECTED) {
      onrejected(this.reason)
    }
    // console.log(this.status)   // PENDING
    // 要点 8: 定时器执行resolve时,状态仍然是pending
    if (this.status === PENDING) {
      // 要点 10: 一个 promise 实例可以被 then 多次,存放 成功回调事件
      this.onfulfilledCallbacks.push(() => {
        onfulfilled(this.value)
      })
      // 要点 10: 一个 promise 实例可以被 then 多次,存放 失败回调事件
      this.onrejectedCallbacks.push(() => {
        onrejected(this.reason)
      })
    }
  }
}
// Commonjs规范导出模块
module.exports = Promise

myPromise — 链式调用(重难点,不好理解)

链式调用这一部分,比较绕,不太好理解,我的老师鼓励我,说:“书读百遍,其义自现”,哈哈哈,现在用来鼓励大家吧!!!test.js。

let Promise = require('./myPromise')

let p = new Promise((resolve, reject) => {
  resolve('成功')
})

// 可以分别注释用例代码,进行效果演示
p.then((data) => {
  return data // 用例1. 返回的是普通值: ‘成功’
  // throw new Error()     // 用例2. 报错或异常: 抛出异常,会直接走下一次then的失败
  // return new Error()    // 用例3. 返回的是普通值: error对象,需要特别注意
  // return new Promise((s,j)=>s(1))    // 用例4. 返回的是promise: 会传递当前promise的已成功结果
  // return new Promise((s,j)=>j(1))    // 用例5. 返回的是promise: 会传递当前promise的已失败结果
}).then((data) => {
  console.log(data, 2) // 执行结果:用例1, 用例3, 用例4
}, (err) => {
  console.log(err, 3) // 执行结果:用例2, 用例5
})

// 1. 返回的是普通值:不论then是成功还是失败。只要是普通值就传递到下一次then的成功中。(普通值包括:非错误非promise,包括对象)
// 2. 报错或异常:一定会走到下一次then的失败中。如果离自己最近的then没有错误处理,会向下找
// 3. 特别注意: return new Error()返回的是错误对象,属于普通值走下一次then的成功,而throw new Error() 是抛出异常,会走下一次的失败
// 4. 返回的是promise:会采用promise的状态,决定下一次then是成功还是失败,此处会有递归判断
// 5. 总结: 如果返回一个普通值,除了promise ,就传递给下一个then的成功,如果返回一个失败的promise或者抛出异常(try catch),会走下一个then的失败

myPromise.js

const RESOLVED = 'RESOLVED'
const REJECTED = 'REJECTED'
const PENDING = 'PENDING'
const resolvePromise = (promise2, x, resolve, reject) => {
  if (promise2 === x) { // 防止自己等待自己 一直循环等待 
    // 原生返回:return reject(new TypeError('TypeError: Chaining cycle detected for promise #<Promise>'))
    return reject(new TypeError('我们自己报的错:循环引用报错'))
  }
  let called; // 为了兼容其他promise 库符合a+规范,防止状态改变后再次被调用
  // 考虑其他promise库兼容问题:判断x是不是promise:不是null的对象  || 函数  
  if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    try { // 为防止then时 出现异常,Object.defineProperty
      let then = x.then // 取x 的then 方法 
      /**
       * 可能对象是{then:{}},还需要判断then是否是函数,
       * 是函数就认为是promise,并调用then方法
       */
      if (typeof then === 'function') {
        // call第一个参数是this,后面的是成功回调 和 失败回调
        // 如果成功回调返回值 y 仍然是promise,就继续递归解析promise,解析到返回值不是一个Promise类型为止
        // promise2能否成功,是根据x的值来定的,x是promise,那么就要等到x完成,x完成后,如果返回y又是promise,那promise2又要等到y完成
        then.call(x, y => {
          if (called) return
          called = true
          resolvePromise(promise2, y, resolve, reject)
        }, e => {
          if (called) return
          called = true
          reject(e)
        })
      } else {
        // 否则就认为 then 是一个普通对象,成功即可
        resolve(x)
      }
    } catch (e) {
      if (called) return
      called = true
      reject(e) // 出现异常,直接走失败逻辑
    }
  } else { // x 为普通值
    resolve(x)
  }
}
class Promise {
  constructor(executor) {
    this.status = PENDING
    this.value = undefined
    this.reason = undefined
    this.onfulfilledCallbacks = []
    this.onrejectedCallbacks = []
    let resolve = (value) => {
      if (this.status === PENDING) {
        this.value = value
        this.status = RESOLVED
        this.onfulfilledCallbacks.forEach(fn => fn())
      }
    }
    let reject = (reason) => {
      if (this.status === PENDING) {
        this.reason = reason
        this.status = REJECTED
        this.onrejectedCallbacks.forEach(fn => fn())
      }
    }
    try {
      executor(resolve, reject)
    } catch (e) {
      reject(e)
    }
  }

  then(onfulfilled, onrejected) {
    // 要点 12: then链式调用,返回的并不是this,而是一个`新的promise实例`
    let promise2 = new Promise((resolve, reject) => { // new Promise执行器中的代码是立即执行,因此没有影响
      if (this.status === RESOLVED) {
        // 加定时器是因为在当前执行上下文中,不能获取promise2的值
        setTimeout(() => {
          // 要点13.2. 用于报错或抛出异常处理,以下同理
          try {
            // 要点13:存储第一次then的回调结果返回值,用于下次then的参数传递,以下let x 同理
            let x = onfulfilled(this.value)
            // 要点13.3: x 可能会是一个promise, 需要单独处理,
            // 并将promise2、新的返回值:x 、成功回调resolve  失败回调reject 作为参数传递
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            // 要点13.2. 报错或抛出异常处理,直接走promise2的reject,以下同理
            reject(e)
          }
        })
      }
      // 以下逻辑同理
      if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            let x = onrejected(this.reason)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
      }
      if (this.status === PENDING) {
        // 暂存成功回调队列
        this.onfulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onfulfilled(this.value)
              resolvePromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          })
        })
        // 暂存失败回调队列
        this.onrejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onrejected(this.reason)
              resolvePromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          })
        })
      }
    })
    return promise2 // 要点 12: 返回一个新的promise实例
  }
}

// Commonjs规范导出模块
module.exports = Promise

myPromise — 值的透传

Promise 值的穿透,当一个promise连续then多次 ,并且then中没有返回任何值时,此时data会穿透值最后一个then中test.js。

//原生方法:值的穿透 演示
let p = new Promise((resolve, reject) => {
  resolve(1)
  // reject(2)   // 同理
})
p.then().then().then(data => {
  console.log(data); // 1
})
p.then().then().then(null, err => {
  console.log(err); // 2
})

// ----------------------------------------------------------

//myPromise:基于以上几部分的实现,我们自己的promise是不支持穿透的,那么看一下演变过程,就很容易写出符合规范的透传
const Promise = require('./myPromise')
let p1 = new Promise((resolve, reject) => {
  resolve(1)
})
let p2 = new Promise((resolve, reject) => {
  reject(2) // 同理,
})

// 相当于, 啥都不写时,感觉像是默认定义了一个函数,不停向下传递,去实现一下吧~
p1.then(data => data)
  .then(data => data)
  .then(data => {
    console.log(data);
  })

// 相当于, throw err,不停向下传递
p2.then(null, err => {
  throw err
}).then(null, err => {
  console.log(err);
  throw err
}).then(null, err => {
  console.log(err);
})

myPromise.js

const RESOLVED = 'RESOLVED'
const REJECTED = 'REJECTED'
const PENDING = 'PENDING'
const resolvePromise = (promise2, x, resolve, reject) => {
  if (promise2 === x) { // 防止自己等待自己 一直循环等待
    // 原生返回:return reject(new TypeError('TypeError: Chaining cycle detected for promise #<Promise>'))
    return reject(new TypeError('我们自己报的错:循环引用报错'))
  }
  let called; // 为了兼容其他promise 库符合a+规范,防止状态改变后再次被调用
  // 考虑其他promise库兼容问题:判断x是不是promise:不是null的对象  || 函数
  if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    try { // 为防止then时 出现异常,Object.defineProperty
      let then = x.then // 取x 的then 方法
      /**
       * 可能对象是{then:{}},还需要判断then是否是函数,
       * 是函数就认为是promise,并调用then方法
       */
      if (typeof then === 'function') {
        // call第一个参数是this,后面的是成功回调 和 失败回调
        // 如果成功回调返回值 y 仍然是promise,就继续递归解析promise,解析到返回值不是一个Promise类型为止
        // promise2能否成功,是根据x的值来定的,x是promise,那么就要等到x完成,x完成后,如果返回y又是promise,那promise2又要等到y完成
        then.call(x, y => {
          if (called) return
          called = true
          resolvePromise(promise2, y, resolve, reject)
        }, e => {
          if (called) return
          called = true
          reject(e)
        })
      } else {
        // 否则就认为 then 是一个普通对象,成功即可
        resolve(x)
      }
    } catch (e) {
      if (called) return
      called = true
      reject(e) // 出现异常,直接走失败逻辑
    }
  } else { // x 为普通值
    resolve(x)
  }
}
class Promise {
  constructor(executor) {
    this.status = PENDING
    this.value = undefined
    this.reason = undefined
    this.onfulfilledCallbacks = []
    this.onrejectedCallbacks = []
    let resolve = (value) => {
      if (this.status === PENDING) {
        this.value = value
        this.status = RESOLVED
        this.onfulfilledCallbacks.forEach(fn => fn())
      }
    }
    let reject = (reason) => {
      if (this.status === PENDING) {
        this.reason = reason
        this.status = REJECTED
        this.onrejectedCallbacks.forEach(fn => fn())
      }
    }
    try {
      executor(resolve, reject)
    } catch (e) {
      reject(e)
    }
  }

  then(onfulfilled, onrejected) {
    // onfulfilled 是函数就执行,不是函数包一层函数并直接返回数据
    onfulfilled = typeof onfulfilled === 'function' ? onfulfilled : v => v;
    // onrejected 是函数就执行,不是函数包一层函数并直接抛出错误
    onrejected = typeof onrejected === 'function' ? onrejected : err => {
      throw err
    };
    // 要点 12: then链式调用,返回的并不是this,而是一个`新的promise实例`
    let promise2 = new Promise((resolve, reject) => { // new Promise执行器中的代码是立即执行,因此没有影响
      if (this.status === RESOLVED) {
        // 加定时器是因为在当前执行上下文中,不能获取promise2的值
        setTimeout(() => {
          // 要点13.2. 用于报错或抛出异常处理,以下同理
          try {
            // 要点13:存储第一次then的回调结果返回值,用于下次then的参数传递,以下let x 同理
            let x = onfulfilled(this.value)
            // 要点13.3: x 可能会是一个promise, 需要单独处理,
            // 并将promise2、新的返回值:x 、成功回调resolve  失败回调reject 作为参数传递
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            // 要点13.2. 报错或抛出异常处理,直接走promise2的reject,以下同理
            reject(e)
          }
        })
      }
      // 以下逻辑同理
      if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            let x = onrejected(this.reason)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
      }
      if (this.status === PENDING) {
        // 暂存成功回调队列
        this.onfulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onfulfilled(this.value)
              resolvePromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          })
        })
        // 暂存失败回调队列
        this.onrejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onrejected(this.reason)
              resolvePromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          })
        })
      }
    })
    return promise2 // 要点 12: 返回一个新的promise实例
  }
}

// Commonjs规范导出模块
module.exports = Promise








































































 
 
 
 
 
 




























































完美通过官方用例

为了测试myPromise库,必须公开一个非常小的适配器接口。可以说是promise的延迟对象defer,下文会详细介绍,各位稍安勿躁。

  • 第一步:找到文件最下面。加上下面几行代码,
/**
   *   ...
   * 其余不变
   *   ...
   */
// 测试自己的写的promise 是否符合a+规范
// promise的延迟对象
Promise.defer = Promise.deferred = function () {
  let dfd = {}
  dfd.promise = new Promise((resolve, reject) => {
    dfd.resolve = resolve;
    dfd.reject = reject
  })
  return dfd;
}

module.exports = Promise
  • 第二步:安装测试包 npm install promises-aplus-tests -g

  • 第三步:进入对应目录执行 promises-aplus-tests ./myPromise.js

myPromise的延迟对象defer用法

promise是为了解决异步回调函数嵌套问题,那么可以通过promise的延迟对象来减少一层嵌套关系

  • 模拟数据准备,准备以下两个文件:
    • name.txt:文件内容是:age.txt
    • age.txt:文件内容18

需求:首先通过fs模块读取到name中的内容(读到新的filepath),再去读取age.txt中的内容并输出。

没有延迟对象的写法:

const fs = require('fs')
const Promise = require('./myPromise')

function read(filepath){
  // 想要read方法可以使用then方法,需要包一层new Promise
  return new Promise((resolve,reject) => {
    fs.readFile(filepath,'utf8',function(err,data){
      if(err) return reject(err)
      resolve(data)
    })
  })
}

read('./name.txt').then(data=>{
  return read(data)    // data = age.txt
}).then(data=>{
  console.log(data);   // data = age.txt
})

使用延迟对象的写法:

const fs = require('fs')
const Promise = require('./myPromise')

function readDefer(filepath){
  let dfd = Promise.defer()   // 减少一层嵌套
  fs.readFile(filepath,'utf8',function(err,data){
    if(err) return dfd.reject(err)
    dfd.resolve(data)
  })
  return dfd.promise
}

readDefer('./name.txt').then(data=>{
  return readDefer(data) // data = age.txt
}).then(data=>{
  console.log(data);    // data = age.txt
})

myPromise.catch

完成以上内容,就已经实现了Promise A+ 规范的全部内容,而我们常用的catch及finally并不属于 A+规范,同样可以实现一下,catch是属于实例上的方法,用于出错处理及捕获异常 演变过程:test.js

const Promise = require('./myPromise')

new Promise((resolve, reject) => {
  reject('失败')
}).then(data => { // 第一个then没有错误处理方法,直接会传递到第二个then中
  console.log(data);
}).then(null, err => {
  console.log(err, 'errrrrr'); // 失败 errrrrr
})

// 将上述代码中null优化一下,于是就有了catch方法
new Promise((resolve, reject) => {
  reject('失败')
}).then(data => {
  console.log(data);
}).catch(err => {
  console.log(err, 'errrrrr'); // 失败 errrrrr
})

实现:myPromise.js

class Promise{
  // 重复代码省略
  // constructor(){...}
  // then(){...}

  catch(onrejected){    // 实例的catch
    return this.then(null, onrejected)
  }
}
/**
 * 其余重复代码省略
 */

myPromise.finally

finally方法是属于实例上的方法.表示无论成功还是失败,都会执行,并且可以向下执行。 理解起来有点点绕哈,建议多看几遍吧,test.js

const Promise = require('./myPromise')

let p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    // resolve('成功')  // 1
    reject('失败') // 2
  }, 1000)
}).finally(() => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      // resolve(1000)  // 3 不会采用promise成功的结果,但是会等待执行
      reject(9000) // 4 但是返回一个失败的promise,会走catch,相当于throw new Error
    }, 1000)
  })
}).then(data => {
  console.log(data); // 对应上述不同序号组合,输出结果有所不同,可自行组合实验,下方也会给大家作出总结
}).catch(e => {
  console.log(e, 'catch');
})

/**
 * 整理流程:
 * 组合:
 * 1+3:成功 + 成功 ,走then=>data 返回 1 返回的数据('成功')
 * 1+4:成功 + 失败 ,走then=>err 抛出 4 返回的数据(9000)
 * 2+3:失败 + 成功 ,走then=>err 抛出 2 返回的数据('失败')
 * 2+4:失败 + 失败 ,走then=>err 抛出 4 返回的数据(9000)
 */

实现:myPromise.js

/**
 * 1. finally 传递了一个方法 callback
 * 2. finally 方法相当于一个then,特点就是在函数中返回一个promise,并会等待这个promise的完成
 * 3. Promise.resolve 又会等待 callback执行完成
 */

class Promise {
  // 重复代码省略
  // constructor(){...}
  // then(){...}
  // catch(){...}
  finally(cb) {
    return this.then((data) => { // 成功 || 失败 都会执行
      // Promise.resolve 目的是等待cb() 后的promise完成
      // 成功时调用finally,直接传递this实例成功的数据data,finally方法本身是没有参数的
      return Promise.resolve(cb()).then(() => data)
    }, (err) => {
      // 失败时调用finally,等待Promise.resolve(cb())的执行的结果,当cb结果为失败时,直接以失败的结果直接走catch
      // 而只有在Promise.resolve成功时候,才会去执行.then(()=>{throw err}),抛出this实例reject的err信息
      return Promise.resolve(cb()).then(() => {
        throw err
      })
    })
  }
}
/**
 * 其余重复代码省略
 */

myPromise.resolve

Promise.resolve() 方法会创造一个成功的promsie,属于类上的方法,通过className调用

演变过程:test.js

const Promise = require('./myPromise')
Promise.resolve(200).then(data => {
  console.log(data);     // 200
})
// 等价于
new Promise((resolve, reject) => {
  resolve(200)
}).then(data => {
  console.log(data);     // 200
})

实现:myPromise.js

constructor(executor) {
  /**
   * 其余重复无改动
   */
  let resolve = (value) => {
    // 一个promise直接resolve 另一个promise时,会等待里面的promise执行完,返回成功的执行结果
    if (value instanceof Promise) {
      return value.then(resolve, reject)
    }
    if (this.status === PENDING) {
      this.value = value
      this.status = RESOLVED
      this.onfulfilledCallbacks.forEach(fn => fn())
    }
  }
  let reject = (reason) => {
    // reject 一个promise时,不需要单独处理,失败就直接走失败的逻辑,不用处理其返回值
    if (this.status === PENDING) {
      this.reason = reason
      this.status = REJECTED
      this.onrejectedCallbacks.forEach(fn => fn())
    }
  }
  /**
   * 其余重复无改动
   */
}

static resolve(value) {
  return new Promise((resolve, reject) => {
    resolve(value)
  })
}

myPromise.reject

Promise.reject() 方法会创造一个失败的promsie,属于类上的方法,通过className调用。

演变过程:test.js

const Promise = require('./myPromise')

Promise.reject(100).then(null,err => {
  console.log(err, 'errrrrr');   // 100 errrrrr
})

// 等价于
new Promise((resolve, reject) => {
  reject(100)
}).then(data=>{
  console.log(data);
},err => {
  console.log(err, 'errrrrr');    // 100 errrrrr
})

实现:myPromise.js

class Promise{
  /**
   * 其余重复无改动
   */
  static reject(reason) {
    return new Promise((resolve, reject) => {
      reject(reason)
    })
  }
}
/**
 * 其余重复无改动
 */

myPromise.all

Promise.all()方法用于将多个 Promise 实例,包装并返回一个新的 Promise 实例p

p的状态由传递的多个 Promise 决定,分成两种情况。(官网是这样说的)

(1)只有所有promise实例的状态都变成fulfilled,p的状态才会变成fulfilled,此时数组中promise的返回值组成一个数组,传递给p的回调函数。

(2)只要数组的中promise有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

test.js

const Promise = require('./myPromise')
Promise.all([
  1, 2, 3,
  new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('成功')
    }, 1000)
  }),
  new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('成功')    // 情况1
      // reject('失败')  // 情况2
    }, 1000)})
  ]).then(data => {
    console.log(data);   // 情况1. [ 1, 2, 3, '成功', '成功' ]
  }).catch(err => {
    console.log(err);    // 情况2. 失败
  })

myPromise.js

class Promise{
  // 在原有代码基础上,添加一个静态方法
  static all(promises){
    return new Promise((resolve,reject)=>{
      let result = []
      let times = 0
      const processSuccess = (index,val)=>{
        result[index] = val
        if(++times === promises.length){
          resolve(result)
        }
      }
      for (let i = 0; i < promises.length; i++) { // 并发。多个请求一起执行
        let p = promises[i];
        if(p && typeof p.then === 'function'){   // 判断p是不是promise实例,是则继续等待p的执行结果,处理p对应的成功和失败
          p.then(data=>{
            processSuccess(i,data)
          },reject) // 如果其中一个promise失败了,直接执行失败回调,由于reject本身就是函数,故可简写
        }else{   // 如果不是promise实例就直接调用成功,并存储该值
          processSuccess(i,p)
        }
      }
    })
  }
}

myPromise.race

Promise.race()方法同样是将多个 Promise 实例,包装并返回一个新的 Promise 实例p。 只要有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。

(简单理解:race 赛跑,采用最快的那一个,race方法如果其中一个完成了,其他方法还是会执行完,只是并没有采用他的结果)

test.js

const Promise = require('./myPromise')
Promise.race([
  new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('成功')
    }, 2000)
  }),
  new Promise((resolve, reject) => {
    setTimeout(() => {
      reject('失败')
    }, 1000)
  })
]).then(data => {
  console.log(data);
}).catch(err => {
  console.log(err);   // 输出:失败,resolve 2s执行,reject 1s执行,reject更快
})

myPromise.js

class Promise{
  static race(promises){
    return new Promise((resolve,reject)=>{
      // for循环执行,只要有一个状态发生改变,就直接将该实例的返回值 返回
      for (let i = 0; i < promises.length; i++) {
        let p = promises[i];
        if(p && typeof p.then === 'function'){
          p.then(data=>{
            resolve(data)
          },reject)
        }else{
          resolve(p)
        }
      }
    })
  }
}

myPromise终极版本

const RESOLVED = 'RESOLVED'
const REJECTED = 'REJECTED'
const PENDING = 'PENDING'
const resolvePromise = (promise2, x, resolve, reject) => {
  if (promise2 === x) {
    return reject(new TypeError('循环引用报错'))
  }
  if (x !== null && (typeof x === 'object' || typeof x === 'function')) {

    let called;
    try {
      let then = x.then
      if (typeof then === 'function') {
        then.call(x, y => {
          if (called) return
          called = true
          resolvePromise(promise2, y, resolve, reject)
        }, e => {
          if (called) return
          called = true
          reject(e)
        })
      } else {
        resolve(x)
      }
    } catch (e) {
      if (called) return
      called = true
      reject(e)
    }
  } else {
    resolve(x)
  }
}
class Promise {
  constructor(executor) {
    this.status = PENDING
    this.value = undefined
    this.reason = undefined
    this.onfulfilledCallbacks = []
    this.onrejectedCallbacks = []
    let resolve = (value) => {
      if (value instanceof Promise) {
        return value.then(resolve, reject)
      }
      if (this.status === PENDING) {
        this.value = value
        this.status = RESOLVED
        this.onfulfilledCallbacks.forEach(fn => fn())
      }
    }
    let reject = (reason) => {
      if (this.status === PENDING) {
        this.reason = reason
        this.status = REJECTED
        this.onrejectedCallbacks.forEach(fn => fn())
      }
    }

    try {
      executor(resolve, reject)
    } catch (e) {
      reject(e)
    }
  }
  then(onfulfilled, onrejected) {
    onfulfilled = typeof onfulfilled === 'function' ? onfulfilled : v => v;
    onrejected = typeof onrejected === 'function' ? onrejected : err => {
      throw err
    };
    let promise2 = new Promise((resolve, reject) => {
      if (this.status === RESOLVED) {
        setTimeout(() => {
          try {
            let x = onfulfilled(this.value)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
      }
      if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            let x = onrejected(this.reason)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
      }
      if (this.status === PENDING) {
        this.onfulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onfulfilled(this.value)
              resolvePromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          })
        })
        this.onrejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onrejected(this.reason)
              resolvePromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          })
        })
      }
    })
    return promise2
  }
  catch (onrejected) {
    return this.then(null, onrejected)
  } finally(cb) {
    return this.then(
      (data) => {
        return Promise.resolve(cb()).then(() => data)
      }, (err) => {
        return Promise.resolve(cb()).then(() => {
          throw err
        })
      })
  }
  static resolve(value) {
    return new Promise((resolve, reject) => {
      resolve(value)
    })
  }
  static reject(reason) {
    return new Promise((resolve, reject) => {
      reject(reason)
    })
  }
  static all(promises) {
    return new Promise((resolve, reject) => {
      let result = []
      let times = 0
      const processSuccess = (index, val) => {
        result[index] = val
        if (++times === promises.length) {
          resolve(result)
        }
      }
      for (let i = 0; i < promises.length; i++) {
        let p = promises[i];
        if (p && typeof p.then === 'function') {
          p.then(data => {
            processSuccess(i, data)
          }, reject)
        } else {
          processSuccess(i, p)
        }
      }
    })
  }
  static race(promises) {
    return new Promise((resolve, reject) => {
      for (let i = 0; i < promises.length; i++) {
        let p = promises[i];
        if (p && typeof p.then === 'function') {
          p.then(data => {
            resolve(data)
          }, reject)
        } else {
          resolve(p)
        }
      }
    })
  }
}

Promise.defer = Promise.deferred = function () {
  let dfd = {}
  dfd.promise = new Promise((resolve, reject) => {
    dfd.resolve = resolve;
    dfd.reject = reject
  })
  return dfd;
}

module.exports = Promise
贡献者: mankueng