2. 手写Promise
1.什么是 Promise?
Promise 是⼀种⽤于异步编程的 JavaScript 对象。主要⽤于处理异步操作的结果。
异步导致的问题:回调地狱(让代码难以阅读)、错误处理(⽆法统⼀处理错误)、多个异步操作(“同步结果”困难)
- Promise 可以使⽤.then()⽅法链式处理异步逻辑 
- Promise 可以使⽤.catch()⽅法处理异步操作失败的情况 
- Promise 提供.all()、.race()⽅法⽀持处理多个 Promise 对象的结果。 
2.⼿写 Promise
2.1 Promise基础版本实现
- 每个 promise 都有三个状态 pending 等待态 fulfilled 成功态 rejected 失败态。 
- 每个 promise 需要有⼀个 then ⽅法,.then()⽅法接受两个回调函数,⼀个是成功的回调另⼀个是失败的回调。 
- new Promise 中传递的函数会⽴即执⾏。 
- promise 对象的状态⼀旦更改后,即不能再改变。(⼀旦成功就不能失败,⼀旦失败就不能成功)。 
- 当 promise 抛出异常后,也会变为失败态。 
const Promise = require("./1.promise")
let promise = new Promise((resolve, reject) => {
  //默认pending状态
  // resolve 和 reject可以改变promise的状态,调⽤then的时候会检测状态来触发对应的函数
  throw new Error("error") // 在代码中发⽣异常也是会触发失败的情况
  resolve("success")
  reject("error")
})
promise.then(
  (value) => {
    // 成功的回调
    console.log("success", value)
  },
  (reason) => {
    // 失败的回调
    console.log("fail", reason)
  }
)
// 1.promise默认三个状态
const PENDING = "PENDING"
const FULFILLED = "FULFILLED"
const REJECTED = "REJECTED"
class Promise {
  constructor(executor) {
    // 2.⽤户传⼊⼀个
    executor
    this.status = PENDING
    this.value = undefined // 成功的值
    this.reason = undefined // 失败的原因
    const resolve = (value) => {
      if (this.status === PENDING) {
        this.status = FULFILLED
        this.value = value
      }
    }
    const reject = (reason) => {
      if (this.status === PENDING) {
        this.status = REJECTED
        this.reason = reason
      }
    }
    try {
      executor(resolve, reject) // 3.这个代码执⾏的时候可能会发⽣异常
    } catch (e) {
      reject(e)
    }
  }
  then(onFulfilled, onRejected) {
    // 4.调⽤then的时候来判断成功还是失败
    if (this.status === FULFILLED) {
      onFulfilled(this.value)
    }
    if (this.status === REJECTED) {
      onRejected(this.reason)
    }
  }
}
module.exports = Promise
2.2 Promise异步情况处理
- 调⽤ then 时 promise 的状态可能还是等待态,此时会将成功的回调和失败的回调收集起来,等待状态变化时在调⽤对应的回调。 (订阅) 
- 同⼀个 promise 对象多次调⽤ then ⽅法。当成功或失败的时候这些回调会按照注册顺序被依次执⾏。(发布) 
const Promise = require("./1.promise")
let promise = new Promise((resolve, reject) => {
  //默认pending状态
  setTimeout(() => {
    resolve("success") // 500ms后成功
  }, 500)
})
promise.then(
  (value) => {
    // 成功的回调
    console.log("success", value)
  },
  (reason) => {
    // 失败的回调
    console.log("fail", reason)
  }
)
promise.then(
  (value) => {
    // 成功的回调
    console.log("success", value)
  },
  (reason) => {
    // 失败的回调
    console.log("fail", reason)
  }
)
// success success
// success success
class Promise {
  constructor(executor) {
    // ...
    this.onResolvedCallbacks = [] // 存放成功的回调
    this.onRejectedCallbacks = [] // 存放失败的回调
    const resolve = (value) => {
      if (this.status === PENDING) {
        // ...
        this.onResolvedCallbacks.forEach((fn) => fn()) //成功时调⽤
      }
    }
    const reject = (reason) => {
      if (this.status === PENDING) {
        // ...
        this.onRejectedCallbacks.forEach((fn) => fn()) //失败时调⽤
      }
    }
    try {
      executor(resolve, reject)
    } catch (e) {
      reject(e)
    }
  }
  then(onFulfilled, onRejected) {
    // ...
    if (this.status === PENDING) {
      // 等待态分别存⼊回调
      this.onResolvedCallbacks.push(() => {
        onFulfilled(this.value)
      })
      this.onRejectedCallbacks.push(() => {
        onRejected(this.reason)
      })
    }
  }
}
2.3 Promise链式调⽤
const fs = require("fs")
const path = require("path")
fs.readFile(
  path.resolve(__dirname, "fileUrl.txt"),
  "utf-8",
  function (err, data) {
    if (err) {
      return console.log(err)
    }
    fs.readFile(path.resolve(__dirname, data), "utf-8", function (err, data) {
      if (err) {
        return console.log(err)
      }
      console.log(data) // 获取最终的结果
    })
  }
)
上⼀个异步输出的结果,是下⼀个的输⼊,会导致回调嵌套问题(回调地狱问题 、恶魔⾦⼦塔)
解决⽅案采⽤ promise,将逻辑改变成链式调⽤
promise 中的 then ⽅法可以传递两个参数 (成功和失败的回调),这两个⽅法都可以返回值。
- 返回的是 promise 对象,外层的下⼀次 then 会⽤这个 promise 的状态来决定⾛的是成功还是失败。 
- 返回的是⼀个普通值的情况 (不是 promise) 就会执⾏下⼀次的成功 (会将返回的值向下传递) 
- 如果抛出异常会执⾏外层下⼀次的 then 的失败。 
function readFile(utl) {
  return new Promise((resolve, reject) => {
    fs.readFile(utl, "utf-8", function (err, data) {
      if (err) return reject(err)
      resolve(data)
    })
  })
}
readFile(path.resolve(__dirname, "fileUrl.txt"))
  .then((data) => {
    return readFile(path.resolve(__dirname, data))
  })
  .then((data) => {
    console.log(data) // 1
    return 123
  })
  .then((data) => {
    // 2
    console.log("success", data)
    throw new Error() // 3
  })
  .then(null, (err) => console.log(err))
总结:就是返回值决定下⼀次 then ⾛成功还是失败,promise 为了实现链式调⽤需要返回了⼀个全新的 promise,这⾥不能返回 this,因为同⼀个实例不能从成功变为失败。
class Promise {
  // ...
  then(onFulfilled, onRejected) {
    // 不停的创建新的promise,来实现链式调⽤
    let promise2 = new Promise((resolve, reject) => {
      if (this.status === FULFILLED) {
        setTimeout(() => {
          // 为了保证promise2已经产⽣
          try {
            let x = onFulfilled(this.value)
            // ⽤x来决定promise2是执⾏成功还是失败
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            // 执⾏对应的回调时发⽣异常就执⾏promise2的失败
            reject(e)
          }
        }, 0)
      }
      // 其它情况也是⼀样来处理...
    })
    return promise2
  }
}
2.4 resolvePromise实现
因为所有的 promise 都是按照 Promisea+规范来实现的,所以可以做到互相组合使⽤。此⽅法需要解决不同的 promise 库之间的调⽤问题。
1) x 和 promise2 引⽤同⼀个值
const promise2 = new Promise((resolve, reject) => {
  resolve("ok")
}).then((data) => {
  return promise2 // 返回的 promise2 不会成功也不会失败。那就直接⾛失败了
})
promise2.then(null, (err) => {
  console.log(err)
})
function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(
      new TypeError(
        "[TypeError:Chaining cycle detected for promise #<Promise>]"
      )
    )
  }
}
2) 多次取then 可能会发⽣异常
// 其它⼈实现的promise可能是这样实现的~
let promise = {}
let times = 0
Object.defineProperty(promise, "then", {
  get() {
    if (++times === 2) {
      throw new Error()
    }
  },
})
promise.then // 第⼀次取then正常
promise.then // 第⼆次取then报错
// 所以要避免多次取then的情况
function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(
      new TypeError(
        "[TypeError:Chaining cycle detected for promise #<Promise>]"
      )
    )
  }
  // 如何判断x是不是promise? 就看有没有then⽅法,有then⽅法的前提得是x是⼀个对象或者函数
  if ((typeof x === "object" && x !== null) || typeof x === "function") {
    try {
      let then = x.then // 缓存then
      if (typeof then === "function") {
        //看then是不是⼀个函数
        // 如果有⼀个then⽅法那么就说他是
        promise
        // 是promise 要判断是成功的promise还是失败的promise,在调⽤promise2对应的resolve或者reject
        then.call(
          x,
          (y) => {
            resolve(y)
          },
          (r) => {
            reject(r)
          }
        )
      } else {
        resolve(x) // 这⾥直接成功即可 普通值的情况
      }
    } catch (e) {
      reject(e) // 直接失败即可
    }
  } else {
    resolve(x) // 这⾥直接成功即可 普通值的情况
  }
}
3) 防⽌重复调⽤
let otherPromise = {
  then(onFulfilled, onRejected) {
    // 别⼈家的promise可能既调⽤了成功⼜调⽤了失败
    throw new Error(onFulfilled("ok"))
    onRejected("no ok")
  },
}
const promise2 = new Promise((resolve, reject) => {
  resolve("ok")
}).then((data) => {
  return otherPromise // 返回的不是⾃⼰的
  promise
})
if ((typeof x === "object" && x !== null) || typeof x === "function") {
  let called = false
  try {
    let then = x.then
    if (typeof then === "function") {
      then.call(
        x,
        (y) => {
          if (called) return // 成功在调⽤失败
          called = true
          resolve(y)
        },
        (r) => {
          if (called) return // 失败在调⽤成功
          called = true
          reject(r)
        }
      )
    } else {
      resolve(x)
    }
  } catch (e) {
    if (called) return // 失败在调⽤成功
    called = true
    reject(e)
  }
} else {
  resolve(x)
}
4) 递归解析
new Promise((resolve, reject) => {
  resolve()
})
  .then(() => {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(
          new Promise((resolve, reject) => {
            setTimeout(() => {
              resolve(100)
            }, 1000)
          })
        )
      }, 1000)
    })
  })
  .then((data) => {
    console.log(data)
  })
then.call(
  x,
  (y) => {
    if (called) return
    called = true
    resolvePromise(promise2, y, resolve, reject) //如果resolve的值还是promise,则递归解析
  },
  (r) => {
    if (called) return
    called = true
    reject(r)
  }
)
2.5 then中可选参数
如果当前 then 中没有处理成功和失败,则会穿透到下⼀个 then 中进⾏处理
const promise1 = new Promise((resolve, reject) => {
  resolve("ok")
})
// 成功的传递
promise1
  .then()
  .then()
  .then((data) => {
    console.log(data)
  })
const promise2 = new Promise((resolve, reject) => {
  reject("fail")
})
// 失败的传递
promise2
  .then()
  .then()
  .then(null, (err) => {
    console.log(err)
  })
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled ==='function' ? onFulfilled : v => v
onRejected = typeof onRejected === 'function'? onRejected : reason => { throw reason }
}
2.6 测试Promise
默认测试的时候会调⽤此⽅法 会检测这个⽅法返回的对象是否符合规范,这个对象上需要有 promise 实例及 resolve 和 reject ⽅法
Promise.deferred = function () {
  let dfd = {}
  dfd.promise = new Promise((resolve, reject) => {
    dfd.resolve = resolve
    dfd.reject = reject
  })
  return dfd
}
npm install promises-aplus-tests -g # 测试包
promises-aplus-tests <filename>
2.7 resolve问题解决
const promise = new Promise((resolve, reject) => {
  // 在ECMAScript中
  // 我们在excutor中resolve⼀个promise会进⾏递归解析
  resolve(
    new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve("ok")
      }, 1000)
    })
  )
}).then((data) => {
  console.log(data) // ok
})
const resolve = (value) => {
  // 如果值是Promise,则需要进⾏递归解析
  if (value instanceof Promise) {
    return value.then(resolve, reject)
  }
  if (this.status === PENDING) {
    this.status = FULFILLED
    this.value = value
    this.onResolvedCallbacks.forEach((fn) => fn())
  }
}
整体代码
// 为了所有人promise 可以互相调用,所以所有的promise都要遵循这个规则
function resolvePromise(promise2, x, resolve, reject) {
  // 这个方法处理的会严谨一些,保证所有人的promise 都可以互相调用
  // If promise and x refer to the same object, reject promise with a TypeError as the reason.
  // 如果x 和 promise2 引用的是同一个对象,那么promise2 要等待x执行完毕
  // x是一个promise,而且永远不会成功和失败,那么就会在这里等待
  if (x === promise2)
    return reject(new TypeError("Chaining cycle detected for promise"))
  // 我如何知道x是不是promise
  if ((typeof x === "object" && x !== null) || typeof x === "function") {
    // 有可能是promise
    // Let then be x.then
    let called = false
    try {
      let then = x.then // then方法可能是通过defineProperty来进行定义的
      if (typeof then === "function") {
        // 是promise  {then:function(){}}
        then.call(
          x,
          (y) => {
            // x.then
            // 为了防止promise解析后的结果依旧是promise,所以需要递归解析
            if (called) return
            called = true
            resolvePromise(promise2, y, resolve, reject)
          },
          (r) => {
            if (called) return
            called = true
            reject(r)
          }
        )
      } else {
        // 就是一个对象或者函数  {a:1}  function(){}
        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.onResolvedCallbacks = []
    this.onRejectedCallbacks = []
    // promise调用then的时候 可能状态依旧是pending,那么我们需要将回调先存放起来
    // 等待过一会调用resolve时触发 onResolvedCallbacks 执行
    // 等待调用 reject时触发onRejectedCallbacks 执行
    const resolve = (value) => {
      //只有状态是pending的时候 才可以修改状态 和 改变成功和失败的原因
      if (value instanceof Promise) {
        // 递归解析的流程
        return value.then(resolve, reject);
      }
      if (this.status === PENDING) {
        this.status = FULFILLED
        this.value = value
        // 成功调用成功的回调
        this.onResolvedCallbacks.forEach((cb) => cb())
      }
    }
    const reject = (reason) => {
      if (this.status === PENDING) {
        this.status = REJECTED
        this.reason = reason
        // 失败调用成功的回调
        this.onRejectedCallbacks.forEach((cb) => cb())
      }
    }
    //  调用executor 会自动传入 resolve 和 reject
    try {
      executor(resolve, reject)
    } catch (e) {
      reject(e)
    }
  }
  // then 的实现
  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (v) => v
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (e) => {
            throw e
          }
    /
    let promise2 = new Promise((resolve, reject) => {
      // 调用then的时候 已经确定了是成功还是失败了
      if (this.status === FULFILLED) {
        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.onResolvedCallbacks.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的实现
  catch(errCallback) {
    return this.then(null, errCallback);
  }
  // Promise.resolve, Promise.reject
  // resolve一个promise 会等待这个promise执行完毕
  // reject 一个promise 会直接失败 不在解析了
  // Promise.resolve 的实现
  static resolve(value) {
    return new Promise((resolve, reject) => {
      resolve(value);
    });
  }
// finally的实现
 finally(callback) {
    return this.then((val)=>{
      return Promise.resolve(callback()).then(()=>val)
    },(err)=>{
      return Promise.resolve(callback()).then(()=>{throw err})
    })
  }
 // Promise.reject 的实现
  static reject(reason) {
    return new Promise((resolve, reject) => {
      reject(reason);
    });
  }
  // Promise.all 的实现
   static all = function (values) {
    // promise 以第一个结果为准,其它的逻辑还是走,只是不采纳了
    // 一个promise返回
    return new Promise((resolve, reject) => {
      // 并发是循环  串行递归
      let arr = [];// 成功的结果
      let times = 0;
      //将当前索引和数据对应
      function processData(index, data) {
        arr[index] = data; // arr[2] = 1;
        if (++times === values.length) {
          resolve(arr);
        }
      }
      for (let i = 0; i < values.length; i++) {
        let cur = values[i]; //cur可能是普通值,页可能是promise,
        //将cur变为一个成功promise,成功保存数据,失败结束
        Promise.resolve(cur).then((data) => {
          processData(i, data);
        }, reject);
      }
    });
  };
 // Promise.race 的实现
   static race = function (values) {
    // promise 以第一个结果为准,其它的逻辑还是走,只是不采纳了
    return new Promise((resolve, reject) => {
      // 并发是循环  串行递归
      for (let i = 0; i < values.length; i++) {
        Promise.resolve(values[i]).then(resolve, reject);
      }
    });
  };
}