kifroom
文章
学习笔记

实现Promise

2025年1月3日 6 分钟阅读 浏览 喜欢 0 评论

要点:

  1. 它有3个状态,pending、fulfilled、rejected,一经改变不可逆转
  2. new Promise接受一个executor()执行器,并立即执行
  3. executor接受resolve和reject
  4. then方法,接受2个参数,成功执行参数1,onFulfilled,参数是成功的值value;失败执行参数2, onRejected,参数是失败的值reason;
  5. then链式调用,值的穿透
  6. catch、finally
  7. all,race,any,allsettled常用方法

基础结构

  1. 它有3个状态,pending、fulfilled、rejected,一经改变不可逆转
  2. new Promise接受一个executor()执行器,并立即执行
  3. executor接受resolve和reject
js
class myPromise {
  constructor(executor) {
    this.state = 'pending'
    this.value = ''
    this.reason = ''
    const resolve = (value) => {
      if (this.state === 'pending') {
        this.state = 'fulfilled'
        this.value = value
      }
    }
    const reject = (reason) => {
      if (this.state === 'pending') {
        this.state = 'rejected'
        this.reason = reason
      }
    }
    try {
      executor(resolve, reject)
    }
    catch (error) {
      reject(error)
    }
  }
}

then方法

then方法,接受2个参数,成功执行参数1,onFulfilled,参数是成功的值value;失败执行参数2, onRejected,参数是失败的值reason;

js
class myPromise {
  constructor(executor) {
    this.state = 'pending'
    this.value = ''
    this.reason = ''
    const resolve = (value) => {
      if (this.state === 'pending') {
        this.state = 'fulfilled'
        this.value = value
      }
    }
    const reject = (reason) => {
      if (this.state === 'pending') {
        this.state = 'rejected'
        this.reason = reason
      }
    }
    try {
      executor(resolve, reject)
    }
    catch (error) {
      reject(error)
    }
  }

  then(onFulFilled, onRejected) {
    if (this.state === 'fulfilled') {
      onFulFilled(this.value)
    }
    if (this.state === 'rejected') {
      onRejected(this.reason)
    }
  }
}

new myPromise((resolve, reject) => {
  reject(1)
}).then((res) => {
  console.log('res', res)
}, (err) => {
  console.log('err', err)
})

截至目前只处理同步操作,如果在 executor()中传入一个异步操作的话就会失效:

js
new myPromise((resolve, reject) => {
  setTimeout(() => { reject(1) }, 2000)
}).then((res) => {
  console.log('res', res)
}, (err) => {
  console.log('err', err)
})

无异步操作

异步任务

在执行then的时候,这个promise的状态还是pending,pending时候不会执行then的2个方法参数的任何一个,所以就没得反应。换句话说,promise只有执行了resolve或reject,状态改变了,才会执行then。所以如果当调用 then 方法时,当前状态是 pending,我们需要先将成功和失败的回调分别存放起来,在executor()的异步任务被执行时,触发 resolve 或 reject,依次调用成功或失败的回调。

js
class myPromise {
  constructor(executor) {
    this.state = 'pending'
    this.value = ''
    this.reason = ''
    this.onFulFilledCallbacks = []
    this.onRejectedCallBacks = []
    const resolve = (value) => {
      if (this.state === 'pending') {
        this.state = 'fulfilled'
        this.value = value
        this.onFulFilledCallbacks.forEach(fn => fn())
      }
    }
    const reject = (reason) => {
      if (this.state === 'pending') {
        this.state = 'rejected'
        this.reason = reason
        this.onRejectedCallBacks.forEach(fn => fn())
      }
    }
    try {
      executor(resolve, reject)
    }
    catch (error) {
      reject(error)
    }
  }

  then(onFulFilled, onRejected) {
    if (this.state === 'fulfilled') {
      onFulFilled(this.value)
    }
    if (this.state === 'rejected') {
      onRejected(this.reason)
    }
    if (this.state === 'pending') {
      this.onFulFilledCallbacks.push(() => {
        onFulFilled(this.value)
      })
      this.onRejectedCallBacks.push(() => {
        onRejected(this.reason)
      })
    }
  }
}

实现异步

then链式调用和值的穿透

  1. 关键点1:then返回的是一个promise,
  2. 关键点2:上一次返回的值可以作为下一个then方法执行的参数

实现关键点1,即:

js
class myPromise {
  constructor(executor) {
    this.state = 'pending'
    this.value = ''
    this.reason = ''
    this.onFulFilledCallbacks = []
    this.onRejectedCallBacks = []
    const resolve = (value) => {
      if (this.state === 'pending') {
        this.state = 'fulfilled'
        this.value = value
        this.onFulFilledCallbacks.forEach(fn => fn())
      }
    }
    const reject = (reason) => {
      if (this.state === 'pending') {
        this.state = 'rejected'
        this.reason = reason
        this.onRejectedCallBacks.forEach(fn => fn())
      }
    }
    try {
      executor(resolve, reject)
    }
    catch (error) {
      reject(error)
    }
  }

  then(onFulFilled, onRejected) {
    let promise2 = new myPromise((resolve, reject) => {
    })
    return promise2
    // if (this.state === "fulfilled") {
    // 	onFulFilled(this.value)
    // }
    // if (this.state === "rejected") {
    // 	onRejected(this.reason)
    // }
    // if (this.state === "pending") {
    // 	this.onFulFilledCallbacks.push(() => {
    // 		onFulFilled(this.value)
    // 	})
    // 	this.onRejectedCallBacks.push(() => {
    // 		onRejected(this.reason)
    // 	})
    // }
  }
}

而promise2内部需要实现之前的内容,同时由于promise 的回调是微任务(microtask),所以需要使用queueMicrotask,再将值传递下去,即:

js
class myPromise {
  constructor(executor) {
    this.state = 'pending'
    this.value = ''
    this.reason = ''
    this.onFulFilledCallbacks = []
    this.onRejectedCallBacks = []
    const resolve = (value) => {
      if (this.state === 'pending') {
        this.state = 'fulfilled'
        this.value = value
        this.onFulFilledCallbacks.forEach(fn => fn())
      }
    }
    const reject = (reason) => {
      if (this.state === 'pending') {
        this.state = 'rejected'
        this.reason = reason
        this.onRejectedCallBacks.forEach(fn => fn())
      }
    }
    try {
      executor(resolve, reject)
    }
    catch (error) {
      reject(error)
    }
  }

  then(onFulFilled, onRejected) {
    const that = this

    let promise2 = new myPromise((resolve, reject) => {
      if (that.state === 'fulfilled') {
        // onFulFilled(that.value)
        try {
          queueMicrotask(() => {
            const result = onFulFilled(that.value)
            resolve(result)
          })
        }
        catch (error) {
          reject(error)
        }
      }
      if (that.state === 'rejected') {
        // onRejected(that.reason)
        try {
          queueMicrotask(() => {
            const result = onRejected(that.reason)
            reject(result)
          })
        }
        catch (error) {
          reject(error)
        }
      }
      if (that.state === 'pending') {
        that.onFulFilledCallbacks.push(() => {
          try {
            queueMicrotask(() => {
              onFulFilled(that.value)
            })
          }
          catch (error) {
            reject(error)
          }
        })
        that.onRejectedCallBacks.push(() => {
          try {
            queueMicrotask(() => {
              onRejected(that.reason)
            })
          }
          catch (error) {
            reject(error)
          }
        })
      }
    })
    return promise2
  }
}

注意到

js
try {
  queueMicrotask(() => {
    onFulFilled(that.value)
  })
}
catch (error) {
  reject(error)
}

部分重复,优化为:

js
class myPromise {
  constructor(executor) {
    this.state = 'pending'
    this.value = ''
    this.reason = ''
    this.onFulFilledCallbacks = []
    this.onRejectedCallBacks = []
    const resolve = (value) => {
      if (this.state === 'pending') {
        this.state = 'fulfilled'
        this.value = value
        this.onFulFilledCallbacks.forEach(fn => fn())
      }
    }
    const reject = (reason) => {
      if (this.state === 'pending') {
        this.state = 'rejected'
        this.reason = reason
        this.onRejectedCallBacks.forEach(fn => fn())
      }
    }
    try {
      executor(resolve, reject)
    }
    catch (error) {
      reject(error)
    }
  }

  then(onFulFilled, onRejected) {
    const that = this
    let promise2 = new myPromise((resolve, reject) => {
      function creatFulfillMicroTask() {
        try {
          queueMicrotask(() => {
            const result = onFulFilled(that.value)
            resolve(result)
          })
        }
        catch (error) {
          reject(error)
        }
      }
      function creatRejectMicroTask() {
        try {
          queueMicrotask(() => {
            const result = onRejected(that.reason)
            reject(result)
          })
        }
        catch (error) {
          reject(error)
        }
      }
      if (that.state === 'fulfilled') {
        creatFulfillMicroTask()
      }
      if (that.state === 'rejected') {
        creatRejectMicroTask()
      }
      if (that.state === 'pending') {
        that.onFulFilledCallbacks.push(creatFulfillMicroTask)
        that.onRejectedCallBacks.push(creatRejectMicroTask)
      }
    })
    return promise2
  }
}

const p1 = new myPromise((resolve, reject) => {
  reject(1)
}).then(
  (res) => {
    console.log('res', res)
    return 'kif'
  },
  (err) => {
    console.log('err', err)
    return 'kif2'
  }
)
p1.then((res) => {
  console.log('res2', res)
}, (err) => {
  console.log('err2', err)
})

console.log('p1', p1)

运行

但是下面运行会出错:

js
new myPromise((resolve, reject) => {
  resolve(1)
}).then().then((res) => {
  console.log('res2', res)
}, (err) => {
  console.log('err2', err)
})

运行

即需要实现值穿透,then没做任何处理的时候,值会往下传,主要在then入口处做处理

js
onFulFilled = typeof onFulFilled === 'function'
  ? onFulFilled
  : v => v
onRejected = typeof onRejected === 'function'
  ? onRejected
  : (error) => {
      throw error
    }
text
reject的方法空时不可以写 v=>v,不然永远都不会走catch,应该v=>{throw v}

全部:

js
function resolvePromise(promise, result, resolve, reject) {
  resolve(result)
}
class myPromise {
  constructor(executor) {
    this.state = 'pending'
    this.value = ''
    this.reason = ''
    this.onFulFilledCallbacks = []
    this.onRejectedCallBacks = []
    const resolve = (value) => {
      if (this.state === 'pending') {
        this.state = 'fulfilled'
        this.value = value
        this.onFulFilledCallbacks.forEach(fn => fn())
      }
    }
    const reject = (reason) => {
      if (this.state === 'pending') {
        this.state = 'rejected'
        this.reason = reason
        this.onRejectedCallBacks.forEach(fn => fn())
      }
    }
    try {
      executor(resolve, reject)
    }
    catch (error) {
      reject(error)
    }
  }

  then(onFulFilled, onRejected) {
    onFulFilled = typeof onFulFilled === 'function'
      ? onFulFilled
      : v => v
    onRejected = typeof onRejected === 'function'
      ? onRejected
      : (error) => {
          throw error
        }
    const that = this
    let promise2 = new myPromise((resolve, reject) => {
      function creatFulfillMicroTask() {
        try {
          queueMicrotask(() => {
            const result = onFulFilled(that.value)
            resolve(result)
          })
        }
        catch (error) {
          reject(error)
        }
      }
      function creatRejectMicroTask() {
        try {
          queueMicrotask(() => {
            const result = onRejected(that.reason)
            reject(result)
          })
        }
        catch (error) {
          reject(error)
        }
      }
      if (that.state === 'fulfilled') {
        // onFulFilled(that.value)
        // try {
        // 	queueMicrotask(() => {
        // 		const result = onFulFilled(that.value);
        // 		resolve(result)
        // 	})
        // } catch (error) {
        // 	reject(error)
        // }
        creatFulfillMicroTask()
      }
      if (that.state === 'rejected') {
        // onRejected(that.reason)
        // try {
        // 	queueMicrotask(() => {
        // 		const result = onRejected(that.reason);
        // 		reject(result);
        // 	})
        // } catch (error) {
        // 	reject(error)
        // }
        creatRejectMicroTask()
      }
      if (that.state === 'pending') {
        that.onFulFilledCallbacks.push(creatFulfillMicroTask)
        that.onRejectedCallBacks.push(creatRejectMicroTask)
      }
    })
    return promise2
  }
}

const p1 = new myPromise((resolve, reject) => {
  resolve(1)
}).then().then((res) => {
  console.log('res2', res)
}, (err) => {
  console.log('err2', err)
})
喜欢 0
评论区在赶来的路上...