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 相关文章推荐
StringTemplate遇见jQuery冲突的解决方法
Sep 22 Javascript
基于JavaScript实现仿京东图片轮播效果
Nov 06 Javascript
JavaScript实现点击按钮直接打印
Jan 06 Javascript
JavaScript小技巧整理篇(非常全)
Jan 26 Javascript
移动端点击图片放大特效PhotoSwipe.js插件实现
Aug 25 Javascript
JS验证 只能输入小数点,数字,负数的实现方法
Oct 07 Javascript
jquery自定义表单验证插件
Oct 12 Javascript
JS改变页面颜色源码分享
Feb 24 Javascript
JS中利用FileReader实现上传图片前本地预览功能
Mar 02 Javascript
vue实现学生录入系统之添加删除功能
Jul 11 Javascript
vue分页器组件编写方法详解
Jun 28 Javascript
JavaScript交换两个变量方法实例
Nov 25 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如何得到当前页和上一页的地址?
2006/11/27 PHP
php实现的太平洋时间和北京时间互转的自定义函数分享
2014/08/19 PHP
thinkphp3.0输出重复两次的解决方法
2014/12/19 PHP
Laravel与CI框架中截取字符串函数
2016/05/08 PHP
Laravel5框架添加自定义辅助函数的方法
2018/08/01 PHP
PHP一个简单的无需刷新爬虫
2019/01/05 PHP
PHP实现笛卡尔积算法的实例讲解
2019/12/22 PHP
javascript实例分享---具有立体效果的图片特效
2014/06/08 Javascript
异步JavaScript编程中的Promise使用方法
2015/07/28 Javascript
jQuery手机拨号界面特效代码分享
2015/08/27 Javascript
js中使用使用原型(prototype)定义方法的好处详解
2016/07/04 Javascript
jquery实现ajax加载超时提示的方法
2016/07/23 Javascript
详解Javascript百度地图接口开发文档中的类和方法
2017/02/07 Javascript
如何正确理解javascript的模块化
2017/03/02 Javascript
Angular.js中上传指令ng-upload的基本使用教程
2017/07/30 Javascript
JavaScript实现点击出现图片并统计点击次数功能示例
2018/07/23 Javascript
vuejs router history 配置到iis的方法
2018/09/20 Javascript
axios使用拦截器统一处理所有的http请求的方法
2018/11/02 Javascript
浅谈Node框架接入ELK实践总结
2019/02/22 Javascript
详解Java中String JSONObject JSONArray List转换
2020/11/13 Javascript
iview实现动态表单和自定义验证时间段重叠
2021/01/10 Javascript
[01:11:37]完美世界DOTA2联赛PWL S2 SZ vs FTD.C 第一场 11.19
2020/11/19 DOTA
Python实现自定义函数的5种常见形式分析
2018/06/16 Python
pytorch中如何使用DataLoader对数据集进行批处理的方法
2019/08/06 Python
python文件绝对路径写法介绍(windows)
2019/12/25 Python
使用PyTorch将文件夹下的图片分为训练集和验证集实例
2020/01/08 Python
pytorch masked_fill报错的解决
2020/02/18 Python
Python文件读写w+和r+区别解析
2020/03/26 Python
Python 实现一行输入多个数字(用空格隔开)
2020/04/29 Python
浅谈css3中的前缀
2016/07/20 HTML / CSS
大学自我鉴定范文
2013/12/26 职场文书
颁奖典礼主持词
2014/03/25 职场文书
2014迎国庆标语大全
2014/09/19 职场文书
合同纠纷调解书
2015/05/20 职场文书
小英雄雨来观后感
2015/06/09 职场文书
情况说明书怎么写
2015/10/08 职场文书