文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

JavaScript手写Promise核心原理

2024-04-02 19:55

关注

准备

我们使用 es6 提供的 class 来实现

class MyPromise {
 // 准备三个状态
 static PENDING = 'pending';
 static FULFILLED = 'fulfilled';
 static REJECTED = 'rejected';

 constructor(executor) {
   this.status = MyPromise.PENDING; // 表示promise的状态
   this.value = null;  // 表示promise的值
   try {
     executor(this.resolve.bind(this), this.reject.bind(this))
   } catch (error) {
     this.reject(error)
   }
 }
 resolve() {
 }
 reject() {
 }
}

在这里 executor 就是传递过来的函数,可以接收 resolvereject,这里将内部的两个方法给传入,如果在调用的过程中报错了会调用reject方法

完善 resolve/reject

他们做的工作分为以下几部

  resolve(value) {
    if (this.status === MyPromise.PENDING) {
      this.status = MyPromise.FULFILLED;
      this.value = value
    }
  }
  reject(value) {
    if (this.status === MyPromise.PENDING) {
      this.status = MyPromise.REJECTED;
      this.value = value
    }
  }

then

then 函数可以接受两个参数,分别为成功的回调函数和失败的回调函数,并且回调函数的默认为一个函数

  then(onFulfilled, onRejected) {
    if (typeof onFulfilled !== 'function') {
      onFulfilled = value => value
    }

    if (typeof onFulfilled !== 'function') {
      onRejected = value => value
    }

    if (this.status === MyPromise.FULFILLED) {
      setTimeout(() => {
        onFulfilled(this.value)
      })
    }

    if (this.status === MyPromise.REJECTED) {
      setTimeout(() => {
        onRejected(this.value)
      })
    }
  }

验证一下:

console.log(1)
new MyPromise((resolve, reject) => {
  console.log(2)
  resolve('成功')
}).then(res => console.log(res))

console.log(3)

// 打印 1 2 3 成功

promise里面有异步代码的时候,这个时候运行到.then方法 状态为pending,下来增加一下异步任务的处理

异步处理

当状态为pending的时候,表示执行的是异步任务,这个时候我们可以增加一个callback,把异步执行的内容添加到这个callback中,当执行完异步代码的时候,会执行异步函数的callback的任务

constructor(executor) {
  // ...
  this.callbacks = []; // 用来存储回调函数的容器
  // ...
}
resolve(value) {
  // ...
  this.callbacks.forEach(({ onFulfilled }) => onFulfilled(value)) 
  // 当执行到这里的时候 如果有onFulfilled 就说明已经执行完then方法给容器添加内容了。把resolve的值传递给onFulfilled
} 
reject(value) {
  // ...
  this.callbacks.forEach(({ onRejected }) => onRejected(value))
  // 当执行到这里的时候 如果有onRejected 就说明已经执行完then方法给容器添加内容了。把reject的值传递给onFulfilled
}
then(onFulfilled, onRejected) {
  // ...
  if (this.status === MyPromise.PENDING) {
    this.callbacks.push({
      onFulfilled: value => {
        setTimeout(() => {
          onFulfilled(value)
        })
      },
      onRejected: value => {
        setTimeout(() => {
          onRejected(value)
        })
      }
    })
  }
 }

验证一下:

new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('成功')
  })
}).then(res => console.log(res)) 

// 打印  成功

then 函数可以链式调用,接下来我们完善一下

链式调用

链式调用的核心就是返回一个新的 promise,当成功调用的时候调用新的promiseresolve,失败reject,并且链式调用会把前一个的返回值当作下一个的 resolve 的状态

then(onFulfilled, onRejected) {
    if (typeof onFulfilled !== 'function') {
      onFulfilled = value => value
    }

    if (typeof onFulfilled !== 'function') {
      onRejected = value => value
    }
    return new MyPromise((resolve, reject) => {
      if (this.status === MyPromise.FULFILLED) {
        setTimeout(() => {
          const result = onFulfilled(this.value)
          resolve(result)
        })
      }

      if (this.status === MyPromise.REJECTED) {
        setTimeout(() => {
          const result = onRejected(this.value)
          resolve(result) 
        })
      }
      if (this.status === MyPromise.PENDING) {
        this.callbacks.push({
          onFulfilled: value => {
            setTimeout(() => {
              const result = onFulfilled(value)
              resolve(result)
            })
          },
          onRejected: value => {
            setTimeout(() => {
              const result = onRejected(value)
              resolve(result)
            })
          }
        })
      }
    })
  }

验证一下:

new MyPromise((resolve, reject) => {
  setTimeout(() => {
    reject('失败')
  })
}).then(res => res, err => err).then(res => console.log(res))

// 打印  失败

如果.then的回调函数返回的是promise的情况也要做个处理

边界处理

实现前:

new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('成功')
  })
}).then(
  res => new MyPromise((resolve, reject) => {
    resolve(res)
  }),
  err => err
).then(res => console.log(res))

// 打印  { "status": "fulfilled", "value": "成功", "callbacks": [] }

当判断返回值为 MyPromise 的时候,需要手动调用 .then 的方法取他的值,并且吧当前的 promise 的改变状态的函数透出给 then 方法

  then(onFulfilled, onRejected) {
    if (typeof onFulfilled !== 'function') {
      onFulfilled = value => value
    }

    if (typeof onFulfilled !== 'function') {
      onRejected = value => value
    }
    return new MyPromise((resolve, reject) => {
      if (this.status === MyPromise.FULFILLED) {
        setTimeout(() => {
          const result = onFulfilled(this.value)
          if (result instanceof MyPromise) { 
            result.then(resolve, reject)
          } else {
            resolve(result)
          }
        })
      }

      if (this.status === MyPromise.REJECTED) {
        setTimeout(() => {
          const result = onRejected(this.value)
          if (result instanceof MyPromise) {
            result.then(resolve, reject)
          } else {
            resolve(result)
          }
        })
      }

      if (this.status === MyPromise.PENDING) {
        this.callbacks.push({
          onFulfilled: value => {
            setTimeout(() => {
              const result = onFulfilled(value)
               if (result instanceof MyPromise) {
                 result.then(resolve, reject)
               } else {
                resolve(result)
               }
            })
          },
          onRejected: value => {
            setTimeout(() => {
              const result = onRejected(value)
              if (result instanceof MyPromise) {
                result.then(resolve, reject)
              } else {
                resolve(result)
              }
            })
          }
        })
      }
    })
  }

验证:

new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('成功')
  })
}).then(
  res => new MyPromise((resolve, reject) => {
    resolve(res)
  }),
  err => err
).then(res => console.log(res))

// 打印  成功

到这里 .then 方法就实现差不多了,接下来实现 catch 方法

catch

catch 方法可以处理拒绝的状态和错误的状态:

  catch(onFulfilled) {
    if (typeof onFulfilled !== 'function') {
      onFulfilled = value => value
    }

    return new MyPromise((resolve, reject) => {
      if (this.status === MyPromise.REJECTED) {
        setTimeout(() => {
          const result = onFulfilled(this.value)
          if (result instanceof MyPromise) {
            result.then(resolve, reject)
          } else {
            resolve(result)
          }
        })
      }
    })
  }

验证:

new MyPromise((resolve, reject) => {
  reject('失败')
}).catch(res=> console.log(res))

// 打印  失败

道理其实和 then 是相同的,到这里主功能基本上就差不多了,但是有很多重复的地方,优化一下

优化后完整代码

class MyPromise {
  // 准备三个状态
  static PENDING = 'pending';
  static FULFILLED = 'fulfilled';
  static REJECTED = 'rejected';

  constructor(executor) {
    this.status = MyPromise.PENDING; // 表示promise的状态
    this.value = null;  // 表示promise的值
    this.callbacks = [];
    try {
      executor(this.resolve.bind(this), this.reject.bind(this))
    } catch (error) {
      console.log(error)
      this.reject(error)
    }
  }
  resolve(value) {
    if (this.status === MyPromise.PENDING) {
      this.status = MyPromise.FULFILLED;
      this.value = value
    }
    this.callbacks.forEach(({ onFulfilled }) => onFulfilled(value))
  }
  reject(value) {
    if (this.status === MyPromise.PENDING) {
      this.status = MyPromise.REJECTED;
      this.value = value
    }
    this.callbacks.forEach(({ onRejected }) => onRejected(value))
  }
  parse({ callback, resolve, reject, value = this.value }) {
    setTimeout(() => {
      const result = callback(value)
      if (result instanceof MyPromise) {
        result.then(resolve, reject)
      } else {
        resolve(result)
      }
    })
  }
  then(onFulfilled, onRejected) {
    if (typeof onFulfilled !== 'function') {
      onFulfilled = value => value
    }

    if (typeof onFulfilled !== 'function') {
      onRejected = value => value
    }
    return new MyPromise((resolve, reject) => {
      if (this.status === MyPromise.FULFILLED) {
        this.parse({ callback: onFulfilled, resolve, reject })
      }

      if (this.status === MyPromise.REJECTED) {
        this.parse({ callback: onRejected, resolve, reject })
      }

      if (this.status === MyPromise.PENDING) {
        this.callbacks.push({
          onFulfilled: value => {
            this.parse({ callback: onFulfilled, resolve, reject, value })
          },
          onRejected: value => {
            this.parse({ callback: onRejected, resolve, reject, value })
          }
        })
      }
    })
  }
  catch(onFulfilled) {
    if (typeof onFulfilled !== 'function') {
      onFulfilled = value => value
    }

    return new MyPromise((resolve, reject) => {
      if (this.status === MyPromise.REJECTED) {
        this.parse({ callback: onFulfilled, resolve, reject })
      }
    })
  }
}

到此这篇关于JavaScript手写Promise核心原理的文章就介绍到这了,更多相关JavaScript Promise内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-前端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯