如何手写Promise

一、开始手写

1.Promise首先是个类,因为它可以实例化,我们使用es6提供的class来模拟它,当然构造函数也行,但是写的太烦了,算了算了

2.Promise接受一个立即执行的函数,这个函数又接受两个参数,一个resolve,一个reject

3.Promise包含三种状态,初始状态等待(pending),成功状态(fulFilled),失败状态(rejected)

4.Promise的状态由resolve和reject改变

// 用常量定义三个状态,避免单词写错的小尴尬事件
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

class MyPromise {
  constructor (executor) {
    executor(this.resolve, this.reject)
  }

  status = PENDING

  resolve = () => {
    this.status = FULFILLED
  }
  reject = () => {
    this.status = REJECTED
  }
}
 5.Promise的状态一经改变,就不能再变化,状态已经锁定了
 6.Promise的then方法接受两个函数作为参数,一个成功回调函数,一个失败回调函数,两个函数也接受一个参数,分别表示成功的结果和失败的原因,这两个值由resolve和reject分别传递过来
// 声明了两个参数value和reason来保存成功和失败的结果
// 方便then方法的成功与失败回调使用
// 而Promise的状态改变之后便锁定也很容易实现,在改变status之前判断status是否等于pending
// 如果status !== pending,则代表status已经发生了改变,直接return

class MyPromise {
  constructor (executor) {
    executor(this.resolve, this.reject)
  }

  status = PENDING
  // 成功的值
  value = undefined
  // 失败的原因
  reason = undefined

  resolve = value => {
    if (this.status !== PENDING) return
    this.status = FULFILLED
    this.value = value
  }
  reject = reason => {
    if (this.status !== PENDING) return
    this.status = REJECTED
    this.reason = reason
  }
  then = (successCallback, failCallback) => {
    if (this.status === FULFILLED) {
      successCallback(this.value)
    } else {
      failCallback(this.reason)
    }
  }
}

let p = new MyPromise((res, rej) => {
  console.log(111);
  res("success")
  rej("fail")
})

// 只会执行成功回调
p.then(value => {
  console.log(value);
}, err => {
  console.log(err);
})

 

7.Promise是用来处理异步的,那么我们试着加入异步的逻辑,怎么加?如果执行到then时,status === pending,将then里的方法储存起来,在resolve或reject的最后执行就行啦,类似于回调函数,类似于哈,但不是,你就这么想就行了
class MyPromise {
  constructor (executor) {
    executor(this.resolve, this.reject)
  }

  status = PENDING
  // 成功的值
  value = undefined
  // 失败的原因
  reason = undefined
  // 新增了成功回调
  successCallback = undefined
  // 新增了失败回调
  failCallback = undefined

  resolve = value => {
    if (this.status !== PENDING) return
    this.status = FULFILLED
    this.value = value
    
    // 执行异步逻辑
    this.successCallback && this.successCallback(this.value)
  }
  reject = reason => {
    if (this.status !== PENDING) return
    this.status = REJECTED
    this.reason = reason

    // 执行异步逻辑
    this.failCallback && this.failCallback(this.reason)
  }
  then = (successCallback, failCallback) => {
    if (this.status === FULFILLED) {
      successCallback(this.value)
    } else if (this.status === REJECTED) {
      failCallback(this.reason)
    } else {
      // 此时status为pending,说明处于异步情况,我们需要将成功回调和失败回调存储起来
      // 在resolve()或reject()最后的地方执行
      this.successCallback = successCallback
      this.failCallback = failCallback
    }
  }
}

// 首先then执行了,但是因为res在两秒后才会执行,所以then里的status===pending
// 所以then里的回调不会执行,而是先储存起来
// 2秒后,res执行,成功回调在res的最后执行
// 这就是Promise通过then执行异步逻辑的原因,将同步代码保存起来,放在异步代码的最后执行
let p = new MyPromise((res, rej) => {
  setTimeout(() => {
    res("success")
  }, 2000)
})

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

  

8.Promise的then方法可以多次调用,每次调用的方法可能都不相同,所以我们需要将所有的成功回调与失败回调保存起来全部保存起来,在status改变之后,遍历调用,当然同步代码不影响,因为直接执行了,异步代码因为是保存着的,所以现在我们要用一个数组给他包起来了
 
class MyPromise {
  constructor (executor) {
    executor(this.resolve, this.reject)
  }

  status = PENDING
  // 成功的值
  value = undefined
  // 失败的原因
  reason = undefined
  // 新增成功回调集合
  successCallbackList = []
  // 新增失败回调集合
  failCallbackList = []

  resolve = value => {
    if (this.status !== PENDING) return
    this.status = FULFILLED
    this.value = value
    
    // 执行异步逻辑
    // this.successCallback && this.successCallback(this.value)
    // 数组的shift方法是将截取数组第一个,并返回截取的那个,会改变原数组,如果理解不了的可以for循环
    while (this.successCallbackList.length) this.successCallbackList.shift()(this.value) 
  }
  reject = reason => {
    if (this.status !== PENDING) return
    this.status = REJECTED
    this.reason = reason

    // 执行异步逻辑
    // this.failCallback && this.failCallback(this.reason)
    while (this.failCallbackList.length) this.failCallbackList.shift()(this.value) 
  }
  then = (successCallback, failCallback) => {
    if (this.status === FULFILLED) {
      successCallback(this.value)
    } else if (this.status === REJECTED) {
      failCallback(this.reason)
    } else {
      // 将回调函数保存在数组里,遍历执行
      this.successCallbackList.push(successCallback)
      this.failCallbackList.push(failCallback)
    }
  }
}

let p = new MyPromise((res, rej) => {
  setTimeout(() => {
    res("success")
  }, 2000)
})

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

p.then(value => {
  console.log(222);
}, err => {
  console.log(err);
})

p.then(value => {
  console.log(333);
}, err => {
  console.log(err);
})

  

9.Promise的链式调用,是解决回调地狱的关键。你知道为啥能链式调用吗?现在我们知道Promise对象可以执行.then,所以每次.then过后就返回一个新的Promise就行了。
10.下一个then的参数就是上一个Promise的返回,但是返回分两种,如果是普通值返回,直接返回就可以了,但是如果返回的是一个Promise对象,那么就得执行这个Promise,等待Promise的状态改变再返回这个Promsie的返回值了
class MyPromise {
  constructor (executor) {
    executor(this.resolve, this.reject)
  }

  status = PENDING
  // 成功的值
  value = undefined
  // 失败的原因
  reason = undefined
  // 成功回调集合
  successCallbackList = []
  // 失败回调集合
  failCallbackList = []

  resolve = value => {
    if (this.status !== PENDING) return
    this.status = FULFILLED
    this.value = value
    
    // 执行异步逻辑
    // 数组的shift方法是将截取数组第一个,并返回截取的那个,会改变原数组,如果理解不了的可以for循环
    while (this.successCallbackList.length) this.successCallbackList.shift()(this.value)
  }
  reject = reason => {
    if (this.status !== PENDING) return
    this.status = REJECTED
    this.reason = reason

    // 执行异步逻辑
    while (this.failCallbackList.length) this.failCallbackList.shift()(this.reason) 
  }
  then = (successCallback, failCallback) => {
    // 这里实例化了一个promise2,并且返回它,以供后面链式调用
    let promise2 = new MyPromise((resolve, reject) => {
      if (this.status === FULFILLED) {
        let result = successCallback(this.value)
        // 判断result的类型
        judgeResult(result, resolve, reject)
      } else if (this.status === REJECTED) {
        let result = failCallback(this.reason)
        // 判断result的类型
        judgeResult(result, resolve, reject)
      } else {
        this.successCallbackList.push(successCallback)
        this.failCallbackList.push(failCallback)
      }
    })
    
    return promise2
  }
}

/**
 * 判断result,如果是个值,那就直接resolve
 * 如果是个Promise,那需要执行.then(),根据.then的结果返回
 */
function judgeResult(result, resolve, reject) {
  if (result instanceof MyPromise) {
    result.then(value => resolve(value), error => reject(error))
  } else {
    resolve(result)
  }
}

p.then(value => {
  console.log(value);
  return "p1--success"
}).then(value => {
  console.log(value);
  return new MyPromise((res, rej) => {
    rej("p2--fail")
  })
}).then(undefined, err => {
  console.log(err);
  return new MyPromise((res, rej) => {
    setTimeout(()=> {
      res("p3--async")
    }, 1000)
  })
}).then(value => {
  console.log(value);
})
11.then返回的如果是个Promise,那么这个返回不能是自己,否则就死循环了,这里也要处理一下
  value = undefined
  // 失败的原因
  reason = undefined
  // 成功回调集合
  successCallbackList = []
  // 失败回调集合
  failCallbackList = []

  resolve = value => {
    if (this.status !== PENDING) return
    this.status = FULFILLED
    this.value = value
    
    // 执行异步逻辑
    // 数组的shift方法是将截取数组第一个,并返回截取的那个,会改变原数组,如果理解不了的可以for循环
    while (this.successCallbackList.length) this.successCallbackList.shift()()
  }
  reject = reason => {
    if (this.status !== PENDING) return
    this.status = REJECTED
    this.reason = reason

    // 执行异步逻辑
    while (this.failCallbackList.length) this.failCallbackList.shift()() 
  }
  then = (successCallback, failCallback) => {
    // 这里实例化了一个promise2,并且返回它,以供后面链式调用
    let promise2 = new MyPromise((resolve, reject) => {
      if (this.status === FULFILLED) {
        // 这里为了判断自己有没有返回自己,将所有处理都延时操作了,只有这样,才能取到promise2
        setTimeout(() => {
          let result = successCallback(this.value)
          // 判断result的类型
          judgeResult(promise2, result, resolve, reject)
        }, 0)
      } else if (this.status === REJECTED) {
        // 这里为了判断自己有没有返回自己,将所有处理都延时操作了,只有这样,才能取到promise2
        setTimeout(() => {
          let result = failCallback(this.reason)
          // 判断result的类型
          judgeResult(promise2, result, resolve, reject)
        }, 0)
      } else {
        this.successCallbackList.push(() => {
          // 这里为了判断自己有没有返回自己,将所有处理都延时操作了,只有这样,才能取到promise2
          setTimeout(() => {
            let result = successCallback(this.value)
            // 判断result的类型
            judgeResult(promise2, result, resolve, reject)
          }, 0)
        })
        this.failCallbackList.push(() => {
          // 这里为了判断自己有没有返回自己,将所有处理都延时操作了,只有这样,才能取到promise2
          setTimeout(() => {
            let result = failCallback(this.reason)
            // 判断result的类型
            judgeResult(promise2, result, resolve, reject)
          }, 0)
        })
      }
    })
    
    return promise2
  }
}

/**
 * 判断result,如果是个值,那就直接resolve
 * 如果是个Promise,那需要执行.then(),根据.then的结果返回
 */
function judgeResult(promise2, result, resolve, reject) {
  if(promise2 === result) {
    return reject("别自己返回自己啊喂!!!")
  }
  if (result instanceof MyPromise) {
    result.then(value => resolve(value), error => reject(error))
  } else {
    resolve(result)
  }
}

p.then(value => {
  console.log(value);
  return "p1--success"
}).then(value => {
  console.log(value);
  return new MyPromise((res, rej) => {
    rej("p2--fail")
  })
}).then(undefined, err => {
  console.log(err);
  return new MyPromise((res, rej) => {
    setTimeout(()=> {
      res("p3--async")
    }, 1000)
  })
}).then(value => {
  console.log(value);
})

// 测试不能返回自己
let p2 = p.then((value) => {
  console.log(value);
  return p2
})

p2.then((value)=> {
  console.log(value)
}, (error) => {
  console.log(error)
})

  

12.then方法的参数不是一个函数时,会自动转换成一个value => value的方法
13.Promise中,每个地方产生的错,最终都会被捕获,所以现在把该捕获错误的地方都捕一捕
// 如何捕获失败,用try/catch,在哪里捕获?在你认为会错的地方😀
class MyPromise {
  constructor (executor) {
    try {
      executor(this.resolve, this.reject)
    } catch (error) {
      this.reject(error)
    }
  }

  status = PENDING
  // 成功的值
  value = undefined
  // 失败的原因
  reason = undefined
  // 成功回调集合
  successCallbackList = []
  // 失败回调集合
  failCallbackList = []

  resolve = value => {
    if (this.status !== PENDING) return
    this.status = FULFILLED
    this.value = value
    
    // 执行异步逻辑
    // 数组的shift方法是将截取数组第一个,并返回截取的那个,会改变原数组,如果理解不了的可以for循环
    while (this.successCallbackList.length) this.successCallbackList.shift()()
  }
  reject = reason => {
    if (this.status !== PENDING) return
    this.status = REJECTED
    this.reason = reason

    // 执行异步逻辑
    while (this.failCallbackList.length) this.failCallbackList.shift()() 
  }
  then = (successCallback, failCallback) => {
    // 判断successCallback和failCallback是不是函数,如果不是,转化成一个函数
    successCallback = typeof successCallback === 'function' ? successCallback : value => value
    failCallback = typeof failCallback === 'function' ? failCallback : value => value

    let promise2 = new MyPromise((resolve, reject) => {
      if (this.status === FULFILLED) {
        try {
          setTimeout(() => {
            let result = successCallback(this.value)
            // 判断result的类型
            judgeResult(result, resolve, reject)
          }, 0)
        } catch (error) {
          reject(error)
        }
      } else if (this.status === REJECTED) {
        try {
          setTimeout(() => {
            let result = failCallback(this.reason)
            // 判断result的类型
            judgeResult(result, resolve, reject)
          }, 0)
        } catch (error) {
          reject(error)
        }
      } else {
        this.successCallbackList.push(() => {
          try {
            setTimeout(() => {
              let result = successCallback(this.value)
              // 判断result的类型
              judgeResult(result, resolve, reject)
            }, 0)
          } catch (error) {
            reject(error)
          }
        })
        this.failCallbackList.push(() => {
          try {
            setTimeout(() => {
              let result = failCallback(this.reason)
              // 判断result的类型
              judgeResult(result, resolve, reject)
            }, 0)
          } catch (error) {
            reject(error)
          }
        })
      }
    })
    
    return promise2
  }
}

/**
 * 判断result,如果是个值,那就直接resolve
 * 如果是个Promise,那需要执行.then(),根据.then的结果返回
 */
function judgeResult(promise2, result, resolve, reject) {
  throw(new Error("judgeResult error"))
  if(promise2 === result) {
    return reject("别自己返回自己啊喂!!!")
  }
  if (result instanceof MyPromise) {
    result.then(value => resolve(value), error => reject(error))
  } else {
    resolve(result)
  }
}

let p = new MyPromise((res, rej) => {
  res("success")
})

p.then().then("b").then(value => console.log(value))

 14.Promise包含几个重要的静态方法,all、race、resolve、catch、finally,现在我们实现一下

 

// Promise.all 故名思意,就是等全部,全部成功之后,返回一个Promise对象,成功回调全部返回的数组
// 如果有失败,则会返回一个Promise对象,失败回调第一个失败的返回
static all(array) {
    try {
        if (!(array instanceof Array)) throw(new Error("请传入一个数组好吗"))
        if (array.length == 0) throw(new Error("请不要传入一个空数组好吗"))
        let arr = []
        return new MyPromise((res, rej) => {
            // 这里有个坑,遍历的里面是异步,所以在最后res(arr)会有问题
            // 所以每次arr.push之后,就比较一下两个arr的长度,长度相等说明已经遍历完了,可以执行res(arr)了
            
            for(let item of array) {
                if (item instanceof MyPromise) {
                    item.then(value=> {
                        arr.push(value)
                    }, error => {
                        rej(error)
                    })
                } else {
                    arr.push(item)
                    if(arr.length == array.length) res(arr)
                }
            }
			// return res(arr)
        })
    } catch (error) {
        console.log(error);
    }
}

// Promise.race故名思意,竞争,看谁先结束,返回的Promise就用谁的返回
static race(array) {
    try {
        if (!(array instanceof Array)) throw(new Error("请传入一个数组好吗"))
        if (array.length == 0) throw(new Error("请不要传入一个空数组好吗"))
        return new MyPromise((res, rej) => {
            for(let item of array) {
                if (item instanceof MyPromise) {
                    item.then(value=> {
                        res(value)
                    }, error => {
                        rej(error)
                    })
                } else {
                    res(item)
                }
            }

        })
    } catch (error) {
        console.log(error);
    }
}

// Promise.resolve 参数如果不是Promise对象,直接返回一个成功回调为参数的Promise对象
// 如果参数是Promise对象,那直接返回参数即可
static resolve(params) {
    try {
        if(params instanceof MyPromise) {
            return params
        } else {
            return new MyPromise(res => {
                res(params)
            })
        }
    } catch (error) {
        console.log(error);
    }
}

// Promise.catch就是一个没有成功回调的then
static catch(failCallback) {
    return this.then(null, failCallback)
}

// Promise.finally 
// 不管成功还是失败都要执行
// 回调函数中不包含当前Promise的返回值,也就是callback不传递参数
// 但是会把当前Promise的返回值return出去,所以调用this.then,获取当前Promise的返回值
// 如果finally返回一个Promise,会执行,但是仍然返回当前Promise的返回值,而不是fianlly返回的Promise的返回值
static finally(callback) {
    this.then(value => {
        this.resolve(callback()).then(() => value)
    }, error => {
        this.resolve(callback()).then(() => {
            throw error
        })
    })
} 

p1.then(()=> {
  return "1111"
}).finally(value => {
  console.log(value);	// undefined
  return new MyPromise(res => {
    res("2222")
  })
}).then(value=> {
  console.log(value);	// "1111"
})

  

 

 

posted @ 2025-06-19 09:13  ~小晨晨  阅读(32)  评论(0)    收藏  举报