使用ES6中Class实现手写PromiseA+,完美通过官方872条用例
长
篇
预
警
!
🧡最近忙着事业,又忙着晋升学习,还要搬家,好久没有输出了,不过还是要抽出边边角角的时间,分享一些好的内容,如果对你有所帮助,笔个芯再走吧🧡
废话不多说,相信大多数人,一提到Promsie就能条件反射想到回调地狱,看了ES6官方晦涩难懂的解释,感觉一脸懵逼,害怕面试的时候被问到,答起来完全不知道自己在说什么,那么今天就来帮你解决掉这一大难题。
长篇预警!有点长,可以选择性观看。本篇主要带领你手写一个Promise源码,学完你就会发现:Promise没有你想象中的那么难,如果对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
- 13.1. 返回的是普通值:不论then是成功还是失败。只要是普通值就传递到下一次then的成功中。(普通值包括:非错误非promise,包括对象)
- 13.2. 报错或异常:一定会走到下一次then的失败中。如果离自己最近的then没有错误处理,会向下找- 特别注意: return new Error()返回的是错误对象,属于普通值走下一次then的成功,而throw new Error() 是抛出异常,需要try catch 会走下一次的失败
 
- 13.3. 返回的是promise:会采用promise的状态,决定下一次then是成功还是失败,此处会有递归判断
- 13.4. 总结: 如果返回一个普通值,除了promise ,就传递给下一个then的成功,如果返回一个失败的promise或者抛出异常,会走下一个then的失败
- Promise 值的穿透,当一个promise连续then 多次,并且then中没有返回任何值时,此时data会穿透至最后一个then中- 14.1 执行onfulfilled时,先判断是不是一个function,如果是就直接执行,反之就包一层函数
- 14.2 执行onrejected时,先判断是不是一个function,如果是就直接执行,反之就抛出失败异常
 
- 14.1 执行
- 既然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('./1.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 Promise = require('./1.myPromise')
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('./1.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('./1.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
上面重复的代码是在是太多了,就不在赘述了,怕看着更晕了,来, 找到类中then方法定义的位置,加上下面两行代码,就可以完美实现成功及失败的数据透传
  ...
  ...
  ...
  // 在这里这里...其他都不变
  then(onfulfilled, onrejected) {
    // onfulfilled 是函数就执行,不是函数包一层函数并直接返回数据
    onfulfilled = typeof onfulfilled === 'function' ? onfulfilled : v => v;
    // onrejected 是函数就执行,不是函数包一层函数并直接抛出错误
    onrejected = typeof onrejected === 'function' ? onrejected : err => { throw err };
  ...
  ...
  ...
完美通过官方872条用例
为了测试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 ./1.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('./1.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('./1.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('./1.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('./1.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('./1.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('./1.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('./1.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('./1.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终极版本
😂😂在我耐心终将耗尽之际,终于迎来了终极版
show一下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
🧡🧡🧡Click Me🧡🧡🧡
既然你都看到这了,想必你肯定是感兴趣啦,希望这篇文章对你更加了解Promise有所帮助,后续工作之余还会分享更多实用的技巧和源码分析,点个赞加个关注再走呗

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号