手写一款符合Promise/A+规范的Promise
手写一款符合Promise/A+规范的Promise
长篇预警!有点长,可以选择性观看。如果对Promise源码不是很清楚,还是推荐从头看,相信你认真从头看到尾,并且去实际操作了,肯定会有收获的。主要是代码部分有点多,不过好多都是重复的,不必担心
Promise的一些用法在此不多赘述,本篇主要带领你手写一个Promise源码,学完你就会发现:Promise没有你想象中的那么难
本篇大概分为以下步骤
- 实现简单的同步Promise
- 增加异步功能
- 增加链式调用then
- 增加catch finally方法
- 增加all race 等方法
- 实现一个promise的延迟对象defer
- 最终测试
实现简单的同步Promise
先大概说一下基本概念:
Promise内部维护着三种状态,即pending,resolved和rejected。初始状态是pending,状态可以有pending--->relolved,或者pending--->rejected.不能从resolve转换为rejected 或者从rejected转换成resolved.
即 只要Promise由pending状态转换为其他状态后,状态就不可变更。
ok.知道了这些后,我们开始手撸代码:
注意观看序号 1 2 3 4 5 ...
function Promise(executor){ let that = this; /** 2 定义初始的一些变量 */ that.status = 'pending'; that.value = null; that.reason = null; /** 3 定义初始的成功和失败函数 */ function resolve(value){ /** 4 判断状态是不是初始状态pending * 是就转换状态 否则不转换 * 确保状态的变化后的不可变性 */ if(that.status === 'pending'){ that.status = 'resolved'; that.value = value; } } function reject(reason){ /** 5 同上 */ if(that.status === 'pending'){ that.status = 'rejected'; that.reason = reason; } } /** * 1 Promise中首先传了一个executor,它是一个函数 * executor函数中又传了两个函数,分别是resolve和reject * 很显然 resolve是成功回调,reject是失败的回调 */ executor(resolve,reject); } /** 6 在Promise原型上面定义then方法 * then方法上面有两个回调 一个是成功后的方法 另一个是失败后的方法 * 根据成功或失败的状态去执行相关成功onFilfulled()或者失败onRejected()的回调方法 */ Promise.prototype.then = function(onFilfulled,onRejected){ let that = this; if(that.status === 'resolved'){ /** 7 如果状态已经变更为resolved * 说明resolve方法已经被调用 * 那么此时就执行成功的回调函数onFilfulled * 并传入参数 that.value * */ onFilfulled(that.value); } if(that.status === 'rejected'){ /** 8 同上 * 传入参数 that.reason */ onRejected(that.reason); } } module.exports = Promise;
通过require()引入手撸的Promise
let Promise = require('./myPromise'); let p1 = ()=>{ return new Promise((resolve,reject)=>{ resolve('success.1'); }); } p1().then((data)=>{ console.log(data); // 打印 success.1 },(err)=>{ console.log(err); });
ok.经调用发现 此代码可以实现部分Promise的功能,但仅仅是同步下才有效果。
那异步呢? 别急这就来~:
增加异步功能
注意观看序号 1 2 3 4 5 ...
function Promise(executor){ let that = this; that.status = 'pending'; that.value = null; that.reason = null; /** 1 因为异步不是立即执行 状态不会变更 成功或失败的回调函数也不会执行 * 所以先定义好存放成功或失败回调函数的数组 * 以便将成功或失败的回调函数先保存起来 * */ that.onFilFulledCallbacks = []; that.onRejectedCallbacks = []; function resolve(value){ if(that.status === 'pending'){ that.status = 'resolved'; that.value = value; /** 3 发布 * 等待状态发生变更 * 状态变更后 立即执行之前存放在相应数组中所有的成功或失败的回调函数 * 即 发布 */ that.onFilFulledCallbacks.forEach((fn)=>{ fn(); }); } } function reject(reason){ if(that.status === 'pending'){ that.status = 'rejected'; that.reason = reason; /** 4 同上 */ that.onRejectedCallbacks.forEach((fn)=>{ fn(); }); } } executor(resolve,reject); } Promise.prototype.then = function(onFilfulled,onRejected){ let that = this; if(that.status === 'resolved'){ onFilfulled(that.value); } if(that.status === 'rejected'){ onRejected(that.reason); } /** 2 订阅 * 因为是异步 状态当时并没有立即变更 所以状态还是pending * 此时需要把成功或者失败的回调函数存放到对应的数组中 * 等待状态变更时 再从数组中拿出来去执行 * 即 订阅 * *存放数组时 为了执行时方便 需要把回调函数的外层包裹一层空函数 */ if(that.status === 'pending'){ that.onFilFulledCallbacks.push(function(){ onFilfulled(that.value); }); } if(that.status === 'pending'){ that.onRejectedCallbacks.push(function(){ onRejected(that.reason); }); } } module.exports = Promise;
代码测试:
let Promise = require('./myPromise'); let p1 = ()=>{ return new Promise((resolve,reject)=>{ setTimeout(function(){ resolve('success.1'); // reject('fail.'); },1500); }); } p1().then((data)=>{ console.log(data); // success.1 },(err)=>{ console.log(err); });
可以看到 1.5s后 执行了resolve() 并打印了success.1,至此,我们实现了异步的Promise.其实这里的实现异步的思想就是发布订阅.
en~ok.高能预警
相关推荐
nmgxzm00 2020-11-10
xixixi 2020-11-11
88254251 2020-11-01
MarukoMa 2020-09-02
88234852 2020-09-15
陈旭阳 2020-08-31
whynotgonow 2020-08-19
前端开发Kingcean 2020-07-30
whynotgonow 2020-07-29
bowean 2020-07-08
前端开发Kingcean 2020-07-08
88520191 2020-07-05
前端开发Kingcean 2020-06-27
88481456 2020-06-18
whynotgonow 2020-06-16
88520191 2020-06-13
88520191 2020-06-13
89500297 2020-06-13