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 相关文章推荐
用Div仿showModalDialog模式菜单的效果的代码
Mar 05 Javascript
Javascript学习笔记2 函数
Jan 11 Javascript
终于解决了IE8不支持数组的indexOf方法
Apr 03 Javascript
js实现每日自动换一张图片的方法
May 04 Javascript
jquery遍历函数siblings()用法实例
Dec 24 Javascript
JS中使用DOM来控制HTML元素
Jul 31 Javascript
BootStrap Table 设置height表头与内容无法对齐的问题
Dec 28 Javascript
Javascript基础回顾之(一) 类型
Jan 31 Javascript
总结js中的一些兼容性易错的问题
Dec 18 Javascript
vue监听键盘事件的快捷方法【推荐】
Jul 11 Javascript
30分钟快速实现小程序语音识别功能
Nov 27 Javascript
spring+angular实现导出excel的实现代码
Feb 27 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
Bo-Blog专用的给Windows服务器的IIS Rewrite程序
2007/08/26 PHP
php 各种应用乱码问题的解决方法
2010/05/09 PHP
php下使用strpos需要注意 === 运算符
2010/07/17 PHP
DOM XPATH获取img src值的query
2013/09/23 PHP
php操作MongoDB基础教程(连接、新增、修改、删除、查询)
2014/03/25 PHP
PHP递归获取目录内所有文件的实现方法
2016/11/01 PHP
php实现微信模板消息推送
2018/03/30 PHP
jQuery 开天辟地入门篇一
2009/12/09 Javascript
javascript利用控件对windows的操作实现原理与应用
2012/12/23 Javascript
ionic开发中点击input时键盘自动弹出
2016/12/23 Javascript
详解Nodejs之npm&package.json
2017/06/15 NodeJs
JS SetInterval 代码实现页面轮询
2017/08/11 Javascript
jQuery中过滤器的基本用法示例
2017/10/11 jQuery
bootstrap-table.js扩展分页工具栏(增加跳转到xx页)功能
2017/12/28 Javascript
深入理解es6块级作用域的使用
2019/03/28 Javascript
快速对接payjq的个人微信支付接口过程解析
2019/08/15 Javascript
Vue利用Blob下载原生二进制数组文件
2019/09/25 Javascript
javascript数组的定义及操作实例
2019/11/10 Javascript
vue浏览器返回监听的具体步骤
2021/02/03 Vue.js
[02:39]DOTA2国际邀请赛助威团西雅图第一天
2013/08/08 DOTA
python3使用tkinter实现ui界面简单实例
2014/01/10 Python
python 五子棋如何获得鼠标点击坐标
2019/11/04 Python
opencv设置采集视频分辨率方式
2019/12/10 Python
python目标检测给图画框,bbox画到图上并保存案例
2020/03/10 Python
python dict乱码如何解决
2020/06/07 Python
python简单实现9宫格图片实例
2020/09/03 Python
Python 列表推导式需要注意的地方
2020/10/23 Python
pytho matplotlib工具栏源码探析一之禁用工具栏、默认工具栏和工具栏管理器三种模式的差异
2021/02/25 Python
欢送退休感言
2014/02/08 职场文书
学习雷锋月活动总结
2014/07/03 职场文书
督导岗位职责
2015/02/04 职场文书
军训结束新闻稿
2015/07/17 职场文书
仅用一句SQL更新整张表的涨跌幅、涨跌率的解决方案
2021/05/06 MySQL
Python 游戏大作炫酷机甲闯关游戏爆肝数千行代码实现案例进阶
2021/10/16 Python
nginx中proxy_pass各种用法详解
2021/11/07 Servers
解析python中的jsonpath 提取器
2022/01/18 Python