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 相关文章推荐
获取当前网页document.url location.href区别总结
May 10 Javascript
Javascript 学习笔记 错误处理
Jul 30 Javascript
js实现连个数字相加而不是拼接的方法
Feb 23 Javascript
使用jQuery实现验证上传图片的格式与大小
Dec 03 Javascript
高性能JavaScript DOM编程(1)
Aug 11 Javascript
node.js入门实例helloworld详解
Dec 23 Javascript
js将json格式的对象拼接成复杂的url参数方法
May 25 Javascript
JS冒泡事件与事件捕获实例详解
Nov 25 Javascript
jQuery控制控件文本的长度的操作方法
Dec 05 Javascript
Three.js加载外部模型的教程详解
Nov 10 Javascript
浅谈Vuejs中nextTick()异步更新队列源码解析
Dec 31 Javascript
微信小程序绘制半圆(弧形)进度条
Nov 18 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在获取指定目录下的目录,在获取的目录下面再创建文件,多平台
2011/08/03 PHP
PHP面向对象编程之深入理解方法重载与方法覆盖(多态)
2015/12/24 PHP
解决Yii2邮件发送结果返回成功,但接收不到邮件的问题
2017/05/23 PHP
PHP创建XML接口示例
2019/07/04 PHP
用js实现手把手教你月入万刀(转贴)
2007/11/07 Javascript
javascript jQuery插件练习
2008/12/24 Javascript
javascript学习(二)javascript常见问题总结
2013/01/02 Javascript
JavaScript实现Java中StringBuffer的方法
2015/02/09 Javascript
检测一个函数是否是JavaScript原生函数的小技巧
2015/03/13 Javascript
javascript引用类型指针的工作方式
2015/04/13 Javascript
纯javascript实现分页(两种方法)
2015/08/26 Javascript
Javascript技术难点之apply,call与this之间的衔接
2015/12/04 Javascript
jQuery中的基本选择器用法学习教程
2016/04/14 Javascript
JS实现为动态创建的元素添加事件操作示例
2018/03/17 Javascript
基于mpvue的小程序项目搭建的步骤
2018/05/22 Javascript
解决LayUI表单获取不到data的问题
2018/08/20 Javascript
vue 路由子组件created和mounted不起作用的解决方法
2019/11/05 Javascript
微信小程序缓存支持二次开发封装实现解析
2019/12/16 Javascript
Vue 组件复用多次自定义参数操作
2020/07/27 Javascript
[03:59]5分钟带你了解什么是DOTA2(第二期)
2017/02/07 DOTA
[19:54]夜魇凡尔赛茶话会 第一期02:看图识人
2021/03/11 DOTA
Python中的yield浅析
2014/06/16 Python
python执行等待程序直到第二天零点的方法
2015/04/23 Python
python range()函数取反序遍历sequence的方法
2018/06/25 Python
破解安装Pycharm的方法
2018/10/19 Python
python使用magic模块进行文件类型识别方法
2018/12/08 Python
python分批定量读取文件内容,输出到不同文件中的方法
2018/12/08 Python
如何安装并在pycharm使用selenium的方法
2020/04/30 Python
澳大利亚新奇小玩意网站:Yellow Octopus
2017/12/28 全球购物
美国礼品卡交易网站:Cardpool
2018/08/27 全球购物
侵犯商业秘密的律师函
2015/05/27 职场文书
2015年初中教务处工作总结
2015/07/21 职场文书
范文之农村基层党建工作报告
2019/10/24 职场文书
详解Redis的三种常用的缓存读写策略步骤
2022/05/06 Redis
html中相对位置与绝对位置的具体使用
2022/05/15 HTML / CSS
pd.drop_duplicates删除重复行的方法实现
2022/06/16 Python