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 相关文章推荐
ff下JQuery无法监听input的keyup事件的解决方法
Dec 12 Javascript
iframe窗口高度自适应的实现方法
Jan 08 Javascript
jQuery实现的导航条切换可显示隐藏
Oct 22 Javascript
jQuery实现tab标签自动切换的方法
Feb 28 Javascript
JavaScript判断数组重复内容的两种方法(推荐)
Jun 06 Javascript
原生js实现淘宝购物车功能
Jun 23 Javascript
AngularJs导出数据到Excel的示例代码
Aug 11 Javascript
vue.js todolist实现代码
Oct 29 Javascript
vue js秒转天数小时分钟秒的实例代码
Aug 08 Javascript
记一次Vue.js混入mixin的使用(分权限管理页面)
Apr 17 Javascript
vue中的inject学习教程
Apr 24 Javascript
微信小程序如何再次获取用户授权的方法
May 10 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
东芝TOSHIBA RP-F11电路分析
2021/03/02 无线电
php一句话cmdshell新型 (非一句话木马)
2009/04/18 PHP
PHP 动态随机生成验证码类代码
2010/04/09 PHP
学习php设计模式 php实现模板方法模式
2015/12/08 PHP
PHP实现深度优先搜索算法(DFS,Depth First Search)详解
2017/09/16 PHP
PHP编程一定要改掉的5个不良习惯
2020/09/18 PHP
幻宇的层模拟窗口效果-提供演示和下载
2007/01/20 Javascript
在JavaScript并非所有的一切都是对象
2013/04/11 Javascript
Jquery EasyUI中弹出确认对话框以及加载效果示例代码
2014/02/13 Javascript
手机端网页点击链接触发自动拨打或保存电话的示例代码
2014/08/15 Javascript
jQuery实现的导航下拉菜单效果
2016/07/04 Javascript
javascript内存分配原理实例分析
2017/04/10 Javascript
javascript实现循环广告条效果
2017/12/12 Javascript
微信小程序http连接访问解决方案的示例
2018/11/05 Javascript
JS计算斐波拉切代码实例
2019/09/12 Javascript
JS实现横向跑马灯效果代码
2020/04/20 Javascript
[03:14]2014DOTA2西雅图国际邀请赛 EG战队巡礼
2014/07/07 DOTA
Python的string模块中的Template类字符串模板用法
2016/06/27 Python
python 类详解及简单实例
2017/03/24 Python
Python对ElasticSearch获取数据及操作
2019/04/24 Python
Python3 执行Linux Bash命令的方法
2019/07/12 Python
python利用pytesseract 实现本地识别图片文字
2020/12/14 Python
html5基础教程常用技巧整理
2013/08/20 HTML / CSS
用canvas做一个DVD待机动画的实现代码
2019/04/12 HTML / CSS
美国顶级防滑鞋:Shoes For Crews
2017/03/27 全球购物
莫斯科高科技在线商店:KremlinStore
2019/03/13 全球购物
乌克兰移动电子产品和相关配件的在线商店:iTMag
2020/03/16 全球购物
const char*, char const*, char*const的区别是什么
2014/07/09 面试题
外贸公司实习自我鉴定
2013/09/24 职场文书
大学生个人简历自我评价
2013/11/16 职场文书
总经理秘书岗位职责
2014/03/17 职场文书
本科应届生自荐信
2014/06/29 职场文书
法院个人总结
2015/03/03 职场文书
幼儿园卫生保健制度
2015/08/05 职场文书
Python获取江苏疫情实时数据及爬虫分析
2021/08/02 Python
Python中递归以及递归遍历目录详解
2021/10/24 Python