LOADING...

加载过慢请开启缓存(浏览器默认开启)

loading

手写Promise

2023/3/1

// promise 有一个参数 是一个函数 PromiseA+ 里他叫 execoutor
// 这个函数有两个参数 resolve reject

// PromiseA+规范中规定 : promise 有三个状态 pending fulfilled rejected
// pending (等待状态) 默认初识状态 可以转换为 fulfilled (成功状态) 或者 rejected (失败状态)
// 当转换为 成功 或者 失败 状态后无法转为其他状态
// 成功状态 必须有一个不可改变的值 value
// 失败状态 必须有一个不可改变的原因 reason

// new Promise((resolve,reject)=>{
//     resolve(value) // 成功 接收一个value 状态转换为 fulfilled 不可再次改变
//     reject(reason) // 失败 接收一个 reason 状态转换为 reason 不可再次改变
//     // 当代码抛出异常直接执行 reject
// })

// promiseA+ 规定 要有一个 叫做 then的方法 里面有两个参数 onFulfilled,onRejected 成功有成功的值 失败有失败的原因
// 当状态 state 为 fulfilled 则执行 onFulfilled 传入 this.value 当状态 state为 rejected 则执行 onRejected 传入 this.reason
// onFulfilled, onRejcted 如果他们是函数 则必须分别在 fulfilled, rejected 之后被调用 value或reason 依次作为他们的第一个参数

//  当按照以上要求实现了 一个Promise 类时  promise 就可以简单的使用一下了
//  当 resolve 在 setTimeout内执行 then时 state 还是pending状态

//  我们就需要在then调用的时候,将成功和失败存到各自的数组,一旦reject或者resolve,就调用它们
//  类似于发布订阅,先将then里面的两个函数储存起来,由于一个promise可以有多个then,所以存在同一个数组内。
//  成功或者失败时,forEach调用它们

// 下面就需要解决链式调用了
// promiseA+规定了 then 方法 必须返回一个 promise 并给出了一个示例
// promise2 = promise1.then(onFulfilled, onRejected);
// promiseA=规定 第一个then中返回了一个参数 x 判断x的函数叫做 resolvePromise
// 首先看 x 是不是promise
// 如果是 promise 则取他的结果作为promise2成功的结果
// 所以要比较x 和promise2
// resolvePromise 的参数有 promise2 (默认返回的promise) x 我们自己return的对象 resolve reject
// resolve 和 reject 是 promise2的

// 处理一些参数问题
// A+ 规定 onFulfilled,onRejected都是可选参数,如果他们不是函数,必须被忽略
// onFulfilled返回一个普通的值,成功时直接等于 value => value
// onRejected返回一个普通的值,失败时如果直接等于 value => value,则会跑到下一个then中的onFulfilled中,
// 所以直接扔出一个错误reason => throw err
// A+ 规定onFulfilled或onRejected不能同步被调用,必须异步调用。我们就用setTimeout解决异步问题
// 如果onFulfilled或onRejected报错,则直接返回reject()
class MyPromise {
  constructor(executor) {
    // 状态 初始化 默认值 pending
    this.state = "pending"
    // 成功的值
    this.value = undefined
    // 失败的原因
    this.reason = undefined
    // 成功存放的数组
    this.onResolvedCallbacks = []
    // 失败存放的数组
    this.onRejectedCallbacks = []
    // 成功
    let resolve = (value) => {
      // 如果状态不是pending 不执行
      if (this.state !== "pending") return
      // 将状态改变为 fulfilled
      this.state = "fulfilled"
      // 成功的值
      this.value = value
      // 一旦 resolve 执行 调用成功数组中的函数
      this.onResolvedCallbacks.forEach((fn) => fn())
    }
    // 失败
    let reject = (reason) => {
      // 如果状态不是pending 不执行
      if (this.state !== "pending") return
      // 将状态改变为 rejected
      this.state = "rejected"
      // 失败的原因
      this.reason = reason
      // 一旦 reject 执行 调用失败数组的函数
      this.onRejectedCallbacks.forEach((fn) => fn())
    }
    try {
      // 立即执行函数
      executor(resolve, reject)
    } catch (err) {
      reject(err)
    }
  }
  // then 方法
  then(onFulfilled, onRejected) {
    // onfulfilled 如果不是函数 忽略 onfulfilled 直接返回value
    onFulfilled =
      typeof onFulfilled === "function" ? onFulfilled : (value) => value
    // onRejected如果不是函数,就忽略onRejected,直接扔出错误
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (err) => {
            throw err
          }
    // 声明返回的promise2
    let myPromise2 = new MyPromise((reslove, reject) => {
      // 成功执行 onFulfilled
      if (this.state === "fulfilled") {
        // 异步
        setTimeout(() => {
          try {
            let x = onFulfilled(this.value)
            resolvePromise(myPromise2, x, reslove, reject)
          } catch (err) {
            reject(err)
          }
        })
      }
      // 失败执行 onRejecyed
      if (this.state === "rejected") {
        // 异步
        setTimeout(() => {
          try {
            let x = onRejected(this.reason)
            resolvePromise(myPromise2, x, reslove, reject)
          } catch (err) {
            reject(err)
          }
        })
      }
      // 当状态为 pending 时 将方法存入各自的数组中
      if (this.state === "pending") {
        this.onResolvedCallbacks.push(() => {
          // 异步
          setTimeout(() => {
            try {
              let x = onFulfilled(this.value)
              resolvePromise(myPromise2, x, reslove, reject)
            } catch (err) {
              reject(err)
            }
          })
        })
        this.onRejectedCallbacks.push(() => {
          // 异步
          setTimeout(() => {
            try {
              let x = onRejected(this.reason)
              resolvePromise(myPromise2, x, reslove, reject)
            } catch (err) {
              reject(err)
            }
          })
        })
      }
    })
    return myPromise2
  }
}
// proimiseA+规范规定了一段代码 让不同的promise代码相互套用 叫做 resolvePromise
// let p = new Promise(resolve => {
//             resolve(0);
//         });
// var p2 = p.then(data => {
//         // 循环引用,自己等待自己完成,一辈子完不成
//              return p2;
//         })
// 如果 x === promise2 则会造成循环引用 需要自己等待完成 ===> 如果x待处理pending,则promise必须保持待处理状态,直到xfulfilled或rejected为止。
// 判断 x
// x 不能是null
// 如果x是普通对象 直接resolve(x)
// x是对象或者函数包括(promise) let then = x.then 2、当x是对象或者函数(默认promise)
// 声明了 then
// 如果取 then 报错 则走 reject()
// 如果then 是个函数 则用call执行then 第一个参数是this 后面是成功回调和失败的回调
// 如果成功的回调 还是promise 就递归解析 3 成功和失败只能调用一个 所以设定一个called来防止多次调用

function resolvePromise(promise2, x, resolve, reject) {
  // 循环引用报错
  if (x === promise2) {
    return reject(new TypeError("检测到循环引用"))
  }
  // 防止多次调用
  let called
  // 如果 x 不是null 并且是函数或者对象
  if (x !== null && (typeof x === "object" || typeof x === "function")) {
    try {
      // A+规定 声明then = x.then方法
      let then = x.then
      // 如果 then 是函数 就默认是 promise
      if (typeof then === "function") {
        // 就让then执行 第一个参数是this   后面是成功的回调 和 失败的回调
        then.call(
          (x, y) => {
            // 成功和失败只能调用一个
            if (called) return
            called = true
            // resolve的结果依旧是promise那就继续解析
            resolvePromise(promise2, y, resolve, reject)
          },
          (err) => {
            //成功和失败只能调用一个
            if (called) return
            called = true
            // 失败了就直接返回
            reject(err)
          }
        )
      } else {
        /// 直接成功
        resolve(x)
      }
    } catch (err) {
      //也属于失败
      if (called) return
      called = true
      // 取then出错了就不继续了
      reject(err)
    }
  } else {
    resolve(x)
  }
}

const p = new MyPromise((reslove, reject) => {
  setTimeout(() => {
    reslove(123)
  }, 100)
})
  .then((res) => {
    console.log(res)
    return 444
  })
  .then((res) => {
    console.log(res)
  })

// const p1 = new Promise((reslove,reject)=>{
//         reslove(444);
// })
// p1.then(value =>{
//     console.log(value);
// })
// p1.then(value=>{
//     console.log(value);
// })
showimg