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 相关文章推荐
js实现DIV的一些简单控制
Jun 04 Javascript
js getBoundingClientRect() 来获取页面元素的位置
Nov 25 Javascript
jquery事件preventDefault()方法用法实例
Jan 16 Javascript
jQuery获得子元素个数的方法
Apr 14 Javascript
使用Node.js配合Nginx实现高负载网络
Jun 28 Javascript
javascript运动框架用法实例分析(实现放大与缩小效果)
Jan 08 Javascript
ECMAScript6轮播图实践知识总结
Aug 17 Javascript
微信小程序 合法域名校验出错详解及解决办法
Mar 09 Javascript
JS实现新建文件夹功能
Jun 17 Javascript
jquery根据name取得select选中的值实例(超简单)
Jan 25 jQuery
微信小程序scroll-view实现滚动穿透和阻止滚动的方法
Aug 20 Javascript
用JS实现飞机大战小游戏
Jun 09 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
dedecms防止FCK乱格式化你的代码的修改方法
2007/03/17 PHP
解析PHP强制转换类型及远程管理插件的安全隐患
2014/06/30 PHP
javascript 必知必会之closure
2009/09/21 Javascript
浅谈javascript中的instanceof和typeof
2015/02/27 Javascript
javascript实现数独解法
2015/03/14 Javascript
JQuery datepicker 用法详解
2015/12/25 Javascript
jQuery prototype冲突的2种解决方法(附demo示例下载)
2016/01/21 Javascript
早该知道的7个JavaScript技巧
2016/06/21 Javascript
jquery插件锦集【推荐】
2016/12/16 Javascript
jQuery Ajax全解析
2017/02/13 Javascript
AngulaJS路由 ui-router 传参实例
2017/04/28 Javascript
详解vuejs几种不同组件(页面)间传值的方式
2017/06/01 Javascript
JavaScript实现移动端页面按手机屏幕分辨率自动缩放的最强代码
2017/08/18 Javascript
浅谈PDF.js使用心得
2018/06/07 Javascript
微信小程序授权登陆及每次检查是否授权实例代码
2019/09/18 Javascript
[01:32:22]DOTA2-DPC中国联赛 正赛 Ehome vs VG BO3 第一场 2月5日
2021/03/11 DOTA
python开发之str.format()用法实例分析
2016/02/22 Python
Python两个内置函数 locals 和globals(学习笔记)
2016/08/28 Python
Python操作MySQL数据库的三种方法总结
2018/01/30 Python
windows下添加Python环境变量的方法汇总
2018/05/14 Python
快速解决PyCharm无法引用matplotlib的问题
2018/05/24 Python
Linux CentOS Python开发环境搭建教程
2018/11/28 Python
Python sklearn KFold 生成交叉验证数据集的方法
2018/12/11 Python
利用Python对文件夹下图片数据进行批量改名的代码实例
2019/02/21 Python
Python实现一个带权无回置随机抽选函数的方法
2019/07/24 Python
Python爬取视频(其实是一篇福利)过程解析
2019/08/01 Python
小结Python的反射机制
2020/09/28 Python
python获取天气接口给指定微信好友发天气预报
2020/12/28 Python
Python爬虫scrapy框架Cookie池(微博Cookie池)的使用
2021/01/13 Python
Prototype如何更新局部页面
2013/03/03 面试题
ruby如何进行集成操作?Ruby能进行多重继承吗?
2013/10/16 面试题
建筑专业毕业生推荐信
2013/11/21 职场文书
《从现在开始》教学反思
2014/04/15 职场文书
机械电子工程专业自荐书
2014/06/10 职场文书
小学优秀学生评语
2014/12/29 职场文书
用python开发一款操作MySQL的小工具
2021/05/12 Python