JS手写一个自定义Promise操作示例


Posted in Javascript onMarch 16, 2020

本文实例讲述了JS手写一个自定义Promise操作。分享给大家供大家参考,具体如下:

经常在面试题中会看到,让你实现一个Promsie,或者问你实现Promise的原理,所以今天就尝试利用class类的形式来实现一个Promise

为了不与原生的Promise命名冲突,这里就简单命名为MyPromise.

class MyPromise {
 constructor(executor) {
  let _this = this
  this.state = 'pending' // 当前状态
  this.value = undefined // 存储成功的值
  this.reason = undefined // 存储失败的值
  // 利用发布订阅模式,让Promise支持异步
  this.onFulfilledFunc = [] // 存储成功的回调
  this.onRejectedFunc = [] // 存储失败的回调

  function resolve (value) {
   // Promise对象已经由pending状态改变为了成功态(resolved)或是失败态(rejected)就不能再次更改状态了。因此我们在更新状态时要判断,如果当前状态是pending(等待态)才可更新
   if (_this.state === 'pending') {
    _this.value = value
    //依次执行成功回调
    _this.onFulfilledFunc.forEach(fn => fn(value))
    _this.state = 'resolved'
   }
  }

  function reject (reason) {
   // Promise对象已经由pending状态改变为了成功态(resolved)或是失败态(rejected)就不能再次更改状态了。因此我们在更新状态时要判断,如果当前状态是pending(等待态)才可更新
   if (_this.state === 'pending') {
    _this.reason = reason
    //依次执行失败回调
    _this.onRejectedFunc.forEach(fn => fn(reason))
    _this.state = 'rejected'
   }
  }

  try {
   // 当实例化Promise时,构造函数中就要马上调用传入的executor函数执行
   executor(resolve, reject)
  } catch (error) {
   reject(error)
  }
 }
 _resolvePromise (promise2, x, resolve, reject) {
  // 如果返回了自己的Promise对象,状态永远为等待态(pending),再也无法成为resolved或是rejected,程序会死掉,因此首先要处理它
  if (promise2 === x) {
   reject(new TypeError('Promise存在循环引用'))
  }
  if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
   // x可能是一个promise
   try {
    let then = x.then
    if (typeof then === 'function') {
     then.call(x, (y) => {
      _resolvePromise(promise2, y, resolve, reject)
     })
    } else {
     resolve(x)
    }
   } catch (err) {
    reject(err)
   }
  } else {
   //否则是个普通值
   resolve(x)
  }
 }
 then (onFulfilled, onRejected) {
  let promise2
  onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (val) { return val }
  onRejected = typeof onRejected === 'function' ? onRejected : function (reason) { throw reason }

  if (this.state === 'resolved') {
   promise2 = new MyPromise((resolve, reject) => {
    setTimeout(() => {
     try {
      let x = onFulfilled(this.value)
      this._resolvePromise(promise2, x, resolve, reject)
     } catch (error) {
      reject(error)
     }
    }, 0);
   })
  }

  if (this.state === 'rejected') {
   promise2 = new MyPromise((resolve, reject) => {
    setTimeout(() => {
     try {
      let x = onRejected(this.reason)
      this._resolvePromise(promise2, x, resolve, reject)
     } catch (error) {
      reject(error)
     }
    }, 0);
   })
  }

  if (this.state === 'pending') {
   promise2 = new MyPromise((resolve, reject) => {
    this.onFulfilledFunc.push(() => {
     setTimeout(() => {
      try {
       let x = onFulfilled(this.value)
       this._resolvePromise(promise2, x, resolve, reject)
      } catch (error) {
       reject(error)
      }
     }, 0);
    })

    this.onRejectedFunc.push(() => {
     setTimeout(() => {
      try {
       let x = onRejected(this.reason)
       this._resolvePromise(promise2, x, resolve, reject)
      } catch (error) {
       reject(error)
      }
     }, 0);
    })
   })
  }

  return promise2
 }
}

运行测试:

var promise = new MyPromise((resolve, reject) => {
 console.log(1)
 setTimeout(() => {
  resolve(2)
 }, 1000);
 console.log(3)
}).then(value => console.log(value))

结果真香:

JS手写一个自定义Promise操作示例

感兴趣的朋友可以使用在线HTML/CSS/JavaScript代码运行工具:http://tools.3water.com/code/HtmlJsRun测试上述代码运行效果。

希望本文所述对大家JavaScript程序设计有所帮助。

Javascript 相关文章推荐
javascript打开word文档的方法
Apr 16 Javascript
使用jQuery异步加载 JavaScript脚本解决方案
Apr 20 Javascript
使用typeof方法判断undefined类型
Sep 09 Javascript
JS使用eval()动态创建变量的方法
Jun 03 Javascript
WebSocket+node.js创建即时通信的Web聊天服务器
Aug 08 Javascript
jquery插件bootstrapValidator数据验证详解
Nov 09 Javascript
canvas实现钟表效果
Feb 13 Javascript
JavaScript编写棋盘覆盖代码详解
Aug 28 Javascript
深入浅析ES6 Class 中的 super 关键字
Oct 20 Javascript
用jquery获取select标签中选中的option值及文本的示例
Jan 25 jQuery
微信小程序网络封装(简单高效)
Aug 06 Javascript
Node.js JSON模块用法实例分析
Jan 04 Javascript
JS函数参数的传递与同名参数实例分析
Mar 16 #Javascript
vue css 引入asstes中的图片无法显示的四种解决方法
Mar 16 #Javascript
JS函数本身的作用域实例分析
Mar 16 #Javascript
JavaScript实现tab栏切换效果
Mar 16 #Javascript
vue-cli3使用mock数据的方法分析
Mar 16 #Javascript
vue-cli3.0实现一个多页面应用的历奇经历记录总结
Mar 16 #Javascript
vue从零实现一个消息通知组件的方法详解
Mar 16 #Javascript
You might like
php4的session功能评述(三)
2006/10/09 PHP
php-accelerator网站加速PHP缓冲的方法
2008/07/30 PHP
PHP连接MSSQL方法汇总
2016/02/05 PHP
利用PHP实现一个简单的用户登记表示例
2017/04/25 PHP
javascript判断单选框或复选框是否选中方法集锦
2007/04/04 Javascript
js操作时间(年-月-日 时-分-秒 星期几)
2010/06/20 Javascript
javascript定义函数的方法
2010/12/06 Javascript
JS封装cookie操作函数实例(设置、读取、删除)
2015/11/17 Javascript
jQuery 3.0中存在问题及解决办法
2016/07/15 Javascript
JavaScript浮点数及运算精度调整详解
2016/10/21 Javascript
微信小程序 天气预报开发实例代码源码
2017/01/20 Javascript
详解Angularjs 如何自定义Img的ng-load 事件
2017/02/15 Javascript
JavaScript实现的浏览器下载文件的方法
2017/08/09 Javascript
webpack4打包vue前端多页面项目
2018/09/17 Javascript
JQuery+Bootstrap 自定义全屏Loading插件的示例demo
2019/07/03 jQuery
js实现AI五子棋人机大战
2020/05/28 Javascript
JS实现横向轮播图(中级版)
2020/01/18 Javascript
浅析AST抽象语法树及Python代码实现
2016/06/06 Python
python+pyqt实现右下角弹出框
2017/10/26 Python
python内置函数:lambda、map、filter简单介绍
2017/11/16 Python
opencv实现静态手势识别 opencv实现剪刀石头布游戏
2019/01/22 Python
python Django的web开发实例(入门)
2019/07/31 Python
对Pytorch神经网络初始化kaiming分布详解
2019/08/18 Python
解决python使用list()时总是报错的问题
2020/05/05 Python
python线程里哪种模块比较适合
2020/08/02 Python
Python创建临时文件和文件夹
2020/08/05 Python
Django Model层F,Q对象和聚合函数原理解析
2020/11/12 Python
德国大型和小型家用电器网上商店:Energeto
2019/05/15 全球购物
成功经营餐厅的创业计划书范文
2013/12/26 职场文书
双语教学实施方案
2014/03/23 职场文书
车辆转让协议书
2014/09/24 职场文书
2014年服务员个人工作总结
2014/12/23 职场文书
挂靠协议书
2015/01/27 职场文书
MySQL Threads_running飙升与慢查询的相关问题解决
2021/05/08 MySQL
MYSQL 的10大经典优化案例场景实战
2021/09/14 MySQL
mysql sock文件存储了什么信息
2022/07/15 MySQL