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 相关文章推荐
JQUBar 基于JQUERY的柱状图插件
Nov 23 Javascript
用jquery实现动画跳到顶部和底部(这个比较简单)
Sep 01 Javascript
js支持键盘控制的左右切换立体式图片轮播效果代码分享
Aug 26 Javascript
原生js实现class的添加和删除简单代码
Jul 12 Javascript
flag和jq on 的绑定多个对象和方法(必看)
Feb 27 Javascript
JS+HTML5 FileReader对象用法示例
Apr 07 Javascript
Vue导出json数据到Excel电子表格的示例
Dec 04 Javascript
nginx部署访问vue-cli搭建的项目的方法
Feb 12 Javascript
关闭Vue计算属性自带的缓存功能方法
Mar 02 Javascript
教你如何用Node实现API的转发(某音乐)
Sep 20 Javascript
JavaScript 禁止用户保存图片的实现代码
Apr 28 Javascript
原生js生成图片验证码
Oct 11 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
人大复印资料处理程序_补充篇
2006/10/09 PHP
PHP中图片等比缩放的实例
2013/03/24 PHP
PHP关于IE下的iframe跨域导致session丢失问题解决方法
2013/10/10 PHP
PHP采用curl模仿用户登陆新浪微博发微博的方法
2014/11/07 PHP
从刷票了解获得客户端IP的方法
2015/09/21 PHP
php中yar框架实例用法讲解
2020/12/27 PHP
js DataSet数据源处理代码
2010/03/29 Javascript
JS无法捕获滚动条上的mouse up事件的原因猜想
2012/03/21 Javascript
jQuery判断密码强度实现思路及代码
2013/04/24 Javascript
asm.js使用示例代码
2013/11/28 Javascript
B/S模式项目中常用的javascript汇总
2013/12/17 Javascript
ExtJs动态生成treepanel的Json格式
2015/07/19 Javascript
jQuery使用contains过滤器实现精确匹配方法详解
2016/02/25 Javascript
当jquery ajax遇上401请求的解决方法
2016/05/19 Javascript
js代码实现下拉菜单【推荐】
2016/12/15 Javascript
Nodejs高扩展性的模板引擎 functmpl简介
2017/02/13 NodeJs
Vue分页组件实例代码
2017/04/17 Javascript
封装运动框架实战左右与上下滑动的焦点轮播图(实例)
2017/10/17 Javascript
实例详解vue.js浅度监听和深度监听及watch用法
2018/08/16 Javascript
使用JavaScript破解web
2018/09/28 Javascript
[04:56]经典回顾:前Ehome 与 前LGD
2015/02/26 DOTA
python中__slots__用法实例
2015/06/04 Python
Python制作爬虫采集小说
2015/10/25 Python
Python学习之Anaconda的使用与配置方法
2018/01/04 Python
python采集微信公众号文章
2018/12/20 Python
详解python的argpare和click模块小结
2019/03/31 Python
在PyCharm中实现添加快捷模块
2020/02/12 Python
通过python连接Linux命令行代码实例
2020/02/18 Python
Python的scikit-image模块实例讲解
2020/12/30 Python
Python调用高德API实现批量地址转经纬度并写入表格的功能
2021/01/12 Python
Philosophy美国官网:美国美容品牌
2016/08/15 全球购物
世界上最大的在线旅行社新加坡网站:Expedia新加坡
2016/08/25 全球购物
Kathmandu英国网站:新西兰户外运动品牌
2017/03/27 全球购物
.net面试题
2016/09/17 面试题
党的群众路线教育实践活动对照检查材料
2014/09/22 职场文书
学习十八届四中全会依法治国心得体会
2014/11/03 职场文书