JavaScript基础教程之如何实现一个简单的promise


Posted in Javascript onSeptember 11, 2018

前言

我们在开发过程中大多会用到promise,想必大家对promise的使用都很熟练了,今天我们就来实现一个简单的promise,实现的效果如有出入还往指正。

Promise/A+规范:

  • 首先重新阅读了下A+的规范:
  • promise代表了一个异步操作的最终结果,主要是通过then方法来注册成功以及失败的情况,
  • Promise/A+历史上说是实现了Promise/A的行为并且考虑了一些不足之处,他并不关心如何创建,完成,拒绝Promise,只考虑提供一个可协作的then方法。

术语:

  • promise是一个拥有符合上面的特征的then方法的对象或者方法。
  • thenable是定义了then方法的对象或者方法
  • value是任何合法的js的值(包括undefined,thenable或者promise)
  • exception是一个被throw申明抛出的值
  • reason是一个指明了为什么promise被拒绝

整体结构

我们先来梳理一下整体的结果,以便后续好操作

class MyPromise {
 constructor(fn){
 
 }
 resolve(){

 }
 then(){

 }
 reject(){

 }
 catch(){

 }
}

Promise理论知识

摘抄至 http://es6.ruanyifeng.com/#docs/promise#Promise-all

Promise对象有以下两个特点。

(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。

(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

总结一下就是promise有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败),还有就是状态的改变只能是pending -> fulfilled 或者 pending -> rejected,这些很重要

实现构造函数

现在我们开始实现构造函数

class MyPromise {
 constructor(fn){
 if(typeof fn !== 'function') {
  throw new TypeError(`MyPromise fn ${fn} is not a function`)
 }
 this.state = 'pending';
 this.value = void 0;
 fn(this.resolve.bind(this),this.reject.bind(this))
 }
 ...
}

构造函数接收一个参数fn,且这个参数必须是一个函数,因为我们一般这样使用new Promise((resolve,reject)=>{});
然后初始化一下promise的状态,默认开始为pending,初始化value的值。

fn接收两个参数,resolve、reject

resolve

class MyPromise {
 constructor(fn){
 if(typeof fn !== 'function') {
  throw new TypeError(`MyPromise fn ${fn} is not a function`)
 }
 this.state = 'pending';
 this.value = void 0;
 fn(this.resolve.bind(this),this.reject.bind(this))
 }
 resolve(value){
 if(this.state !== 'pending') return;
 this.state = 'fulfilled';
 this.value = value
 }
 ...
}

当resolve执行,接收到一个值之后;状态就由 pending -> fulfilled;当前的值为接收的值

reject

class MyPromise {
 constructor(fn){
 if(typeof fn !== 'function') {
  throw new TypeError(`MyPromise fn ${fn} is not a function`)
 }
 this.state = 'pending';
 this.value = void 0;
 fn(this.resolve.bind(this),this.reject.bind(this))
 }
 resolve(value){
 if(this.state !== 'pending') return;
 this.state = 'fulfilled';
 this.value = value
 }
 reject(reason){
 if(this.state !== 'pending') return;
 this.state = 'rejected';
 this.value = reason
 }
}

当reject执行,接收到一个值之后;状态就由 pending -> rejected;当前的值为接收的值

then

class MyPromise {
 constructor(fn){
 if(typeof fn !== 'function') {
  throw new TypeError(`MyPromise fn ${fn} is not a function`)
 }
 this.state = 'pending';
 this.value = void 0;
 fn(this.resolve.bind(this),this.reject.bind(this))
 }
 resolve(value){
 if(this.state !== 'pending') return;
 this.state = 'fulfilled';
 this.value = value
 }
 reject(reason){
 if(this.state !== 'pending') return;
 this.state = 'rejected';
 this.value = reason
 }
 then(fulfilled,rejected){
 if (typeof fulfilled !== 'function' && typeof rejected !== 'function' ) {
  return this;
 }
 if (typeof fulfilled !== 'function' && this.state === 'fulfilled' ||
  typeof rejected !== 'function' && this.state === 'rejected') {
  return this;
 }
 return new MyPromise((resolve,reject)=>{
  if(fulfilled && typeof fulfilled === 'function' && this.state === 'fulfilled'){
  let result = fulfilled(this.value);
  if(result && typeof result.then === 'function'){
   return result.then(resolve,reject)
  }else{
   resolve(result)
  }
  }
  if(rejected && typeof rejected === 'function' && this.state === 'rejected'){
  let result = rejected(this.value);
  if(result && typeof result.then === 'function'){
   return result.then(resolve,reject)
  }else{
   resolve(result)
  }
  }
 })
 }
}

then的实现比较关键,首先有两个判断,第一个判断传的两个参数是否都是函数,如果部不是return this执行下一步操作。
第二个判断的作用是,比如,现在状态从pending -> rejected;但是中间代码中有许多个.then的操作,我们需要跳过这些操作执行.catch的代码。如下面的代码,执行结果只会打印1

new Promise((resolve,reject)=>{
 reject(1)
}).then(()=>{
 console.log(2)
}).then(()=>{
 console.log(3)
}).catch((e)=>{
 console.log(e)
})

我们继续,接下来看到的是返回了一个新的promise,真正then的实现的确都是返回一个promise实例。这里不多说

下面有两个判断,作用是判断是rejected还是fulfilled,首先看fulfilled,如果是fulfilled的话,首先执行fulfilled函数,并把当前的value值传过去,也就是下面这步操作,res就是传过去的value值,并执行了(res)=>{console.log(res)}这段代码;执行完成之后我们得到了result;也就是2这个结果,下面就是判断当前结果是否是一个promise实例了,也就是下面注释了的情况,现在我们直接执行resolve(result);

new Promise((resolve,reject)=>{
 resolve(1)
}).then((res)=>{
 console.log(res)
 return 2
 //return new Promise(resolve=>{})
})

剩下的就不多说了,可以debugger看看执行结果

catch

class MyPromise {
 ...
 catch(rejected){
  return this.then(null,rejected)
 }
}

完整代码

class MyPromise {
 constructor(fn){
  if(typeof fn !== 'function') {
   throw new TypeError(`MyPromise fn ${fn} is not a function`)
  }
  this.state = 'pending';
  this.value = void 0;
  fn(this.resolve.bind(this),this.reject.bind(this))
 }
 resolve(value){
  if(this.state !== 'pending') return;
  this.state = 'fulfilled';
  this.value = value
 }
 reject(reason){
  if(this.state !== 'pending') return;
  this.state = 'rejected';
  this.value = reason
 }
 then(fulfilled,rejected){
  if (typeof fulfilled !== 'function' && typeof rejected !== 'function' ) {
   return this;
  }
  if (typeof fulfilled !== 'function' && this.state === 'fulfilled' ||
   typeof rejected !== 'function' && this.state === 'rejected') {
   return this;
  }
  return new MyPromise((resolve,reject)=>{
   if(fulfilled && typeof fulfilled === 'function' && this.state === 'fulfilled'){
    let result = fulfilled(this.value);
    if(result && typeof result.then === 'function'){
     return result.then(resolve,reject)
    }else{
     resolve(result)
    }
   }
   if(rejected && typeof rejected === 'function' && this.state === 'rejected'){
    let result = rejected(this.value);
    if(result && typeof result.then === 'function'){
     return result.then(resolve,reject)
    }else{
     resolve(result)
    }
   }
  })
 }
 catch(rejected){
  return this.then(null,rejected)
 }
}

测试

new MyPromise((resolve,reject)=>{
 console.log(1);
 //reject(2)
 resolve(2)
 console.log(3)
 setTimeout(()=>{console.log(4)},0)
}).then(res=>{
 console.log(res)
 return new MyPromise((resolve,reject)=>{
 resolve(5)
 }).then(res=>{
 return res
 })
}).then(res=>{
 console.log(res)
}).catch(e=>{
 console.log('e',e)
})

执行结果:

> 1
> 3
> 2
> 5
> 4

原生promise

new Promise((resolve,reject)=>{
 console.log(1);
 //reject(2)
 resolve(2)
 console.log(3)
 setTimeout(()=>{console.log(4)},0)
}).then(res=>{
 console.log(res)
 return new Promise((resolve,reject)=>{
 resolve(5)
 }).then(res=>{
 return res
 })
}).then(res=>{
 console.log(res)
}).catch(e=>{
 console.log('e',e)
})

执行结果:

> 1
> 3
> 2
> 5
> 4

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
IE 缓存策略的BUG的解决方法
Jul 21 Javascript
javascript 触发事件列表 比较不错
Sep 03 Javascript
js onload处理html页面加载之后的事件
Oct 30 Javascript
Linux下编译安装php libevent扩展实例
Feb 14 Javascript
jQuery插件zoom实现图片全屏放大弹出层特效
Apr 15 Javascript
简介BootStrap model弹出框的使用
Apr 27 Javascript
vuejs动态组件给子组件传递数据的方法详解
Sep 09 Javascript
详解Webpack DLL用法以及功能
Jul 11 Javascript
SVG动画vivus.js库使用小结(实例代码)
Sep 14 Javascript
元素全屏的设置与监听实例
Nov 28 Javascript
react 国际化的实现代码示例
Sep 14 Javascript
关于vue v-for循环解决img标签的src动态绑定问题
Sep 18 Javascript
Vue监听数据渲染DOM完以后执行某个函数详解
Sep 11 #Javascript
vue2.0$nextTick监听数据渲染完成之后的回调函数方法
Sep 11 #Javascript
Angular6 正则表达式允许输入部分中文字符
Sep 10 #Javascript
vue中使用input[type="file"]实现文件上传功能
Sep 10 #Javascript
详解Eslint 配置及规则说明
Sep 10 #Javascript
bootstrap自定义样式之bootstrap实现侧边导航栏功能
Sep 10 #Javascript
vue弹窗组件的实现示例代码
Sep 10 #Javascript
You might like
在任意字符集下正常显示网页的方法二(续)
2007/04/01 PHP
PHP根据传来的16进制颜色代码自动改变背景颜色
2014/06/13 PHP
php实现读取和写入tab分割的文件
2015/06/01 PHP
PHP7匿名类用法分析
2016/09/26 PHP
ThinkPHP3.2框架自带分页功能实现方法示例
2019/05/13 PHP
经典的带阴影的可拖动的浮动层
2006/06/26 Javascript
js日期、星座的级联显示代码
2014/01/23 Javascript
AngularJS基础知识
2014/12/21 Javascript
JS+CSS实现自动改变切换方向图片幻灯切换效果的方法
2015/03/02 Javascript
JQuery中DOM加载与事件执行实例分析
2015/06/13 Javascript
在JavaScript应用中使用RequireJS来实现延迟加载
2015/07/01 Javascript
JavaScript+CSS实现仿天猫侧边网页菜单效果
2015/08/25 Javascript
浅谈Nodejs观察者模式
2015/10/13 NodeJs
基于JavaScript实现一定时间后去执行一个函数
2015/12/14 Javascript
教你用javascript实现随机标签云效果_附代码
2016/03/16 Javascript
漂亮! js实现颜色渐变效果
2016/08/12 Javascript
jQuery EasyUI编辑DataGrid用combobox实现多级联动
2016/08/29 Javascript
原生JS实现左右箭头选择日期实例代码
2017/03/14 Javascript
Three.js中矩阵和向量的使用教程
2019/03/19 Javascript
微信小程序发布新版本时自动提示用户更新的方法
2019/06/07 Javascript
微信小程序嵌入腾讯视频源过程详解
2019/08/08 Javascript
JavaScript构造函数原理及实现流程解析
2020/11/19 Javascript
python使用smtplib模块通过gmail实现邮件发送的方法
2015/05/08 Python
Python正确重载运算符的方法示例详解
2017/08/27 Python
Django实现快速分页的方法实例
2017/10/22 Python
Python3.7 基于 pycryptodome 的AES加密解密、RSA加密解密、加签验签
2019/12/04 Python
opencv python图像梯度实例详解
2020/02/04 Python
Python接口测试get请求过程详解
2020/02/28 Python
Window系统下Python如何安装OpenCV库
2020/03/05 Python
golang/python实现归并排序实例代码
2020/08/30 Python
英国最大的宠物食品和宠物用品网上零售商: Zooplus
2016/08/01 全球购物
SQL Server面试题
2016/10/17 面试题
肯尼迪就职演说稿
2013/12/31 职场文书
股份合作协议书
2014/09/10 职场文书
参观监狱警示教育心得体会
2016/01/15 职场文书
postgresql 删除重复数据案例详解
2021/08/02 PostgreSQL