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 相关文章推荐
获取页面高度,窗口高度,滚动条高度等参数值getPageSize,getPageScroll
Sep 22 Javascript
javascript之学会吝啬 精简代码
Apr 25 Javascript
Jquery ThickBox插件使用心得(不建议使用)
Sep 08 Javascript
js 可拖动列表实现代码
Dec 13 Javascript
12306验证码破解思路分享
Mar 25 Javascript
JQuery鼠标移到小图显示大图效果的方法
Jun 10 Javascript
jQuery基于ajax实现带动画效果无刷新柱状图投票代码
Aug 10 Javascript
JS实现超精简响应鼠标显示二级菜单代码
Sep 12 Javascript
简单的JS时钟实例讲解
Jan 13 Javascript
AngularJS动态绑定HTML的方法分析
Nov 07 Javascript
vuejs手把手教你写一个完整的购物车实例代码
Jul 06 Javascript
微信小程序实现复选框效果
Dec 28 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
[FAQ]PHP中的一些常识:类篇
2006/10/09 PHP
php 正则表达式小结
2009/08/31 PHP
PHP、Nginx、Apache中禁止网页被iframe引用的方法
2020/10/01 PHP
php 策略模式原理与应用深入理解
2019/09/25 PHP
初窥JQuery(二)事件机制(2)
2010/12/06 Javascript
Mac OS X 系统下安装和部署Egret引擎开发环境
2014/09/03 Javascript
javascript基本类型详解
2014/11/28 Javascript
js数组去重的5种算法实现
2015/11/04 Javascript
Jquery Easyui表单组件Form使用详解(30)
2016/12/19 Javascript
JS验证码实现代码
2017/09/14 Javascript
vue-router路由与页面间导航实例解析
2017/11/07 Javascript
jQuery中复合选择器简单用法示例
2018/03/31 jQuery
JavaScript callback回调函数用法实例分析
2018/05/08 Javascript
使用Sonarqube扫描Javascript代码的示例
2018/12/26 Javascript
Vue服务端渲染实践之Web应用首屏耗时最优化方案
2019/03/22 Javascript
layUI实现列表查询功能
2019/07/27 Javascript
js实现点击图片在屏幕中间弹出放大效果
2019/09/11 Javascript
小程序实现投票进度条
2019/11/20 Javascript
Vue程序化的事件监听器(实例方案详解)
2020/01/07 Javascript
微信小程序实现拼图小游戏
2020/10/22 Javascript
[01:02:25]2014 DOTA2华西杯精英邀请赛 5 24 iG VS DK
2014/05/26 DOTA
python中的多线程实例教程
2014/08/27 Python
Python selenium如何设置等待时间
2016/09/15 Python
Python做简单的字符串匹配详解
2017/03/21 Python
python difflib模块示例讲解
2017/09/13 Python
python 基于opencv 实现一个鼠标绘图小程序
2020/12/11 Python
canvas学习和滤镜实现代码
2018/08/22 HTML / CSS
StubHub德国:购买和出售门票
2017/09/06 全球购物
一份婚庆公司创业计划书
2014/01/11 职场文书
大学生自助营养快餐店创业计划书
2014/01/13 职场文书
迟到检讨书500字
2014/02/05 职场文书
2014年党支部承诺书
2014/05/30 职场文书
安全教育观后感
2015/06/17 职场文书
庆祝教师节主持词
2015/07/06 职场文书
运动员加油词
2015/07/18 职场文书
Java Socket实现Redis客户端的详细说明
2021/05/26 Redis