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 学习笔记一些小技巧
Mar 28 Javascript
限制文本框输入N个字符的js代码
May 13 Javascript
JS设置获取cookies的方法
Jan 26 Javascript
jquery+ajax实现直接提交表单实例分析
Jun 17 Javascript
React实践之Tree组件的使用方法
Sep 30 Javascript
JS实现websocket长轮询实时消息提示的效果
Oct 10 Javascript
JavaScript实现表单注册、表单验证、运算符功能
Oct 15 Javascript
js自定义input文件上传样式
Oct 26 Javascript
vue实现PC端录音功能的实例代码
Jun 05 Javascript
vue中使用 pako.js 解密 gzip加密字符串的方法
Jun 10 Javascript
JS/CSS实现字符串单词首字母大写功能
Sep 03 Javascript
vue实现div可拖动位置也可改变盒子大小的原理
Sep 16 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
php+mysql分页代码详解
2008/03/27 PHP
修改Zend引擎实现PHP源码加密的原理及实践
2008/04/14 PHP
PHP表单提交表单名称含有点号(.)则会被转化为下划线(_)
2011/12/14 PHP
Yii PHP Framework实用入门教程(详细介绍)
2013/06/18 PHP
PHP zip扩展Linux下安装过程分享
2014/05/05 PHP
PHP中防止SQL注入方法详解
2014/12/25 PHP
yii去掉必填项中星号的方法
2015/12/28 PHP
删除重复数据的算法
2006/11/23 Javascript
js 实现无缝滚动 兼容IE和FF
2009/07/15 Javascript
javascript 二分法(数组array)
2010/04/24 Javascript
jquery+json实现分页效果
2016/03/07 Javascript
jQuery删除当前节点元素
2016/12/07 Javascript
bootstrap如何让dropdown menu按钮式下拉框长度一致
2017/04/10 Javascript
Bootstrap响应式导航由768px变成992px的实现代码
2017/06/15 Javascript
微信小程序中使用Promise进行异步流程处理的实例详解
2017/08/17 Javascript
浅析Vue项目中使用keep-Alive步骤
2018/07/27 Javascript
JavaScript高级函数应用之分时函数实例分析
2018/08/03 Javascript
微信小程序自定义波浪组件使用方法详解
2019/09/21 Javascript
2019年度web前端面试题总结(主要为Vue面试题)
2020/01/12 Javascript
Python的Django REST框架中的序列化及请求和返回
2016/04/11 Python
Python中查看文件名和文件路径
2017/03/31 Python
python matplotlib中文显示参数设置解析
2017/12/15 Python
Python一个简单的通信程序(客户端 服务器)
2019/03/06 Python
浅谈tensorflow中Dataset图片的批量读取及维度的操作详解
2020/01/20 Python
HTML5 使用 sessionStorage 进行页面传值的方法
2018/07/02 HTML / CSS
史蒂夫·马登加拿大官网:Steve Madden加拿大
2017/11/18 全球购物
俄罗斯购买内衣网站:Trusiki
2020/08/22 全球购物
Servlet如何得到服务器的信息
2015/12/22 面试题
业务副厂长岗位职责
2014/01/03 职场文书
白血病捐款倡议书
2014/05/14 职场文书
2014年学雷锋活动总结
2014/06/26 职场文书
搞笑结婚保证书
2015/05/08 职场文书
加薪申请报告范本
2015/05/15 职场文书
让世界充满爱观后感
2015/06/10 职场文书
红楼梦读书笔记
2015/06/25 职场文书
Apache压力测试工具的安装使用
2021/03/31 Servers