使用ES6中Class实现手写PromiseA+,完美通过官方872条用例
[toc]
长
篇
预
警
!
🧡最近忙着事业,又忙着晋升学习,还要搬家,好久没有输出了,不过还是要抽出边边角角的时间,分享一些好的内容,如果对你有所帮助,笔个芯再走吧🧡
废话不多说,相信大多数人,一提到Promsie
就能条件反射想到回调地狱
,看了ES6官方晦涩难懂的解释,感觉一脸懵逼,害怕面试的时候被问到,答起来完全不知道自己在说什么,那么今天就来帮你解决掉这一大难题。
长篇预警!有点长,可以选择性观看。本篇主要带领你手写一个Promise源码,学完你就会发现:Promise没有你想象中的那么难,如果对Promise源码不是很清楚,还是推荐从头看,相信你认真从头看到尾,并且去实际操作了,肯定会有收获的。主要是代码部分有点多,不过好多都是重复的,不必担心
Promise出现的原因
promise出现的原因,说白了也就是promise解决了什么问题,这里我就简单说点吧: Promise 是异步编程的一种解决方案,比传统的解决方案回调函数和事件更合理和更强大,Promise的出现主要解决以下两个问题:
- 回调地狱: 某个异步操作需要等待之前的操作完成在继续执行, 当这样的需求多了以后, 使的代码进入无尽的嵌套,可读性降低不好维护
- 异步和同步之间的联系问题:当一个同步操作需要等待多个异步操作的结果, 这样会使得代码的逻辑变得相对来说比较复杂
myPromise的实现要点
- Promise 就是一个类,实际上就是ES6提供的一个新的构造函数,
- 通过
new
创建实例,接收一个函数作为参数,并且该函数中的代码默认是同步代码,会立即执行 - Promise 有三种状态,
成功resolved
,失败rejected
,等待pedding
- Promise 状态一旦发生改变,就不能在改变,状态不可逆
- 用户可自定义
成功的数据
及失败的原因
- Promise 实例拥有一个
then
方法。接受两个参数,一个成功回调,一个失败回调 - executor执行器在执行过程中,可能会抛出异常 throw new Error(),需要 try catch 捕获
- 当执行器中的是异步代码时(如定时器执行resolve),不是立即执行 状态不会变更,此时then方法中状态仍然是
pending
- 一个 promise 实例可以被 then 多次,分别创建一个
队列用来存放成功和失败回调事件
- 定时器执行时,判断状态为 pending,非立即执行,而是先
存放
成功/失败 回调事件 - 等待状态变为成功或失败时
遍历队列依次执行
对应的onfulfilled
和onrejected
,并且有执行顺序 - Promise 实现链式调用,返回的并不是this,而是一个
新的promise实例
, 因为原有的promise状态一旦发生改变,就不能再改变,否则不符合规范 - Promise 成功和失败的回调的返回值,可以传递给下一次的的then
- 13.1.
返回的是普通值
:不论then是成功还是失败。只要是普通值就传递到下一次then的成功中。(普通值包括:非错误非promise,包括对象) - 13.2.
报错或异常
:一定会走到下一次then的失败中。如果离自己最近的then没有错误处理,会向下找特别注意
: return new Error()返回的是错误对象,属于普通值走下一次then的成功,而throw new Error() 是抛出异常,需要try catch 会走下一次的失败
返回的是promise:会采用promise的状态,决定下一次then是成功还是失败,此处会
有递归判断
Promise 值的穿透
,当一个promise连续then 多次,并且then中没有返回任何值时,此时data会穿透至最后一个then中-
14.1 执行
onfulfilled
时,先判断是不是一个function,如果是就直接执行,反之就包一层函数
- 14.2 执行
onrejected
时,先判断是不是一个function,如果是就直接执行,反之就抛出失败异常
- 既然promise是为了解决异步回调函数嵌套问题,那么可以通过promise的延迟对象来减少一层嵌套关系
- promiseA+ 规范测试
- 聊点规范以外的东东吧~~
catch
,finally
,resolve
,reject
,all
,race
,就这么多
myPromise的实现
下面就来实现以上要点
myPromise — 实现简单的同步
myPromise.js
// 要点 3: 有三种状态, 相当于是常量,可以放在外面 const RESOLVED = 'RESOLVED' const REJECTED = 'REJECTED' const PENDING = 'PENDING' // 要点 1: Promise 就是一个类 class Promise { // 要点 2: 接收一个函数executor作为参数,立即执行 constructor(executor) { this.status = PENDING this.value = undefined // 要点 5: 用户可自定义 成功的数据 this.reason = undefined // 要点 5: 用户可自定义 失败的原因 let resolve = (value) => { // 要点 4: 状态不可逆, 只有PENDING时,才可以改变状态 if (this.status === PENDING) { this.value = value // 成功的数据 this.status = RESOLVED // 状态置为 RESOLVED } } let reject = (reason) => { // 要点 4: 状态不可逆, 只有PENDING时,才可以改变状态 if (this.status === PENDING) { this.reason = reason // 失败的原因 this.status = REJECTED // 状态置为 REJECTED } } // 要点 7: 错误处理,抛出异常 throw new Error() try { executor(resolve, reject) // 立即执行 } catch(e) { // 抛出异常 直接失败 reject(e) } } // 要点 6: 拥有一个then方法(实例上的方法)。接受两个参数回调函数 then(onfulfilled, onrejected) { if(this.status === RESOLVED){ onfulfilled(this.value) } if(this.status === REJECTED){ onrejected(this.reason) } } } // Commonjs规范导出模块 module.exports = Promise
test.js:简单的同步操作验证
// 使用自己的promise,注释该行代码,就是原生promise let Promise = require('./1.myPromise') let p = new Promise((resolve, reject) => { resolve('成功') // throw new Error('失败了') // reject('失败') }) p.then((data) => { console.log(data) }, (err) => { console.log(err) })
myPromise — 增加异步功能
在实现了简单的同步操作后,再来看看异步代码的执行,还是使用上面 test 中的案例,简单的改造一下,写一个定时器模拟异步环境,
test.js:增加异步功能
let Promise = require('./1.myPromise') let p = new Promise((resolve, reject) => { setTimeout(()=>{ resolve('成功') },1000) }) p.then((data) => { console.log(data,1) }, (err) => { console.log(err) }) // 一个实例可以then多次,执行结果会是一样的,因为状态已经固定 p.then((data) => { console.log(data,2) }, (err) => { console.log(err) })
myPromise.js
const RESOLVED = 'RESOLVED' const REJECTED = 'REJECTED' const PENDING = 'PENDING' class Promise { constructor(executor) { this.status = PENDING this.value = undefined this.reason = undefined // 要点 9: 分别创建一个`队列用来存放成功和失败回调事件 this.onfulfilledCallbacks = [] this.onrejectedCallbacks = [] let resolve = (value) => { if (this.status === PENDING) { this.value = value this.status = RESOLVED this.onfulfilledCallbacks.forEach(fn => fn()) // 要点 11: 状态变为成功时遍历队列依次执行 } } let reject = (reason) => { if (this.status === PENDING) { this.reason = reason this.status = REJECTED this.onrejectedCallbacks.forEach(fn => fn()) // 要点 11: 状态变为失败时遍历队列依次执行 } } try { executor(resolve, reject) } catch(e) { reject(e) } } then(onfulfilled, onrejected) { if(this.status === RESOLVED){ onfulfilled(this.value) } if(this.status === REJECTED){ onrejected(this.reason) } // console.log(this.status) // PENDING // 要点 8: 定时器执行resolve时,状态仍然是pending if(this.status === PENDING){ // 要点 10: 一个 promise 实例可以被 then 多次,存放 成功回调事件 this.onfulfilledCallbacks.push(() => { onfulfilled(this.value) }) // 要点 10: 一个 promise 实例可以被 then 多次,存放 失败回调事件 this.onrejectedCallbacks.push(() => { onrejected(this.reason) }) } } } // Commonjs规范导出模块 module.exports = Promise
myPromise — 链式调用(重难点,不好理解)
链式调用这一部分,比较绕,不太好理解,我的老师鼓励我,说:“书读百遍,其义自现”,哈哈哈,现在用来鼓励大家吧!!! test.js
let Promise = require('./1.myPromise') let p = new Promise((resolve, reject) => { resolve('成功') }) // 可以分别注释用例代码,进行效果演示 p.then((data) => { return data // 用例1. 返回的是普通值: ‘成功’ // throw new Error() // 用例2. 报错或异常: 抛出异常,会直接走下一次then的失败 // return new Error() // 用例3. 返回的是普通值: error对象,需要特别注意 // return new Promise((s,j)=>s(1)) // 用例4. 返回的是promise: 会传递当前promise的已成功结果 // return new Promise((s,j)=>j(1)) // 用例5. 返回的是promise: 会传递当前promise的已失败结果 }).then((data) => { console.log(data,2) // 执行结果:用例1, 用例3, 用例4 }, (err) => { console.log(err,3) // 执行结果:用例2, 用例5 }) // 1. 返回的是普通值:不论then是成功还是失败。只要是普通值就传递到下一次then的成功中。(普通值包括:非错误非promise,包括对象) // 2. 报错或异常:一定会走到下一次then的失败中。如果离自己最近的then没有错误处理,会向下找 // 3. 特别注意: return new Error()返回的是错误对象,属于普通值走下一次then的成功,而throw new Error() 是抛出异常,会走下一次的失败 // 4. 返回的是promise:会采用promise的状态,决定下一次then是成功还是失败,此处会有递归判断 // 5. 总结: 如果返回一个普通值,除了promise ,就传递给下一个then的成功,如果返回一个失败的promise或者抛出异常(try catch),会走下一个then的失败
myPromise.js
const RESOLVED = 'RESOLVED' const REJECTED = 'REJECTED' const PENDING = 'PENDING' const resolvePromise = (promise2, x, resolve, reject) => { if (promise2 === x) { // 防止自己等待自己 一直循环等待 // 原生返回:return reject(new TypeError('TypeError: Chaining cycle detected for promise #<Promise>')) return reject(new TypeError('我们自己报的错:循环引用报错')) } let called; // 为了兼容其他promise 库符合a+规范,防止状态改变后再次被调用 // 考虑其他promise库兼容问题:判断x是不是promise: 不是null的对象 || 函数 if (x !== null && (typeof x === 'object' || typeof x === 'function')) { try { // 为防止then时 出现异常,Object.defineProperty let then = x.then // 取x 的then 方法 /** * 可能对象是{then:{}},还需要判断then是否是函数, * 是函数就认为是promise,并调用then方法 */ if (typeof then === 'function') { // call第一个参数是this,后面的是成功回调 和 失败回调 // 如果成功回调返回值 y 仍然是promise,就继续递归解析promise,解析到返回值不是一个Promise类型为止 // promise2能否成功,是根据x的值来定的,x是promise,那么就要等到x完成,x完成后,如果返回y又是promise,那promise2又要等到y完成 then.call(x, y =>{ if (called) return called = true resolvePromise(promise2, y, resolve, reject) }, e => { if (called) return called = true reject(e) }) } else { // 否则就认为 then 是一个普通对象,成功即可 resolve(x) } } catch (e) { if (called) return called = true reject(e) // 出现异常,直接走失败逻辑 } } else { // x 为普通值 resolve(x) } } class Promise { constructor(executor) { this.status = PENDING this.value = undefined this.reason = undefined this.onfulfilledCallbacks = [] this.onrejectedCallbacks = [] let resolve = (value) => { if (this.status === PENDING) { this.value = value this.status = RESOLVED this.onfulfilledCallbacks.forEach(fn => fn()) } } let reject = (reason) => { if (this.status === PENDING) { this.reason = reason this.status = REJECTED this.onrejectedCallbacks.forEach(fn => fn()) } } try { executor(resolve, reject) } catch (e) { reject(e) } } then(onfulfilled, onrejected) { // 要点 12: then链式调用,返回的并不是this,而是一个`新的promise实例` let promise2 = new Promise((resolve, reject) => { // new Promise执行器中的代码是立即执行,因此没有影响 if (this.status === RESOLVED) { // 加定时器是因为在当前执行上下文中,不能获取promise2的值 setTimeout(() => { // 要点13.2. 用于报错或抛出异常处理,以下同理 try { // 要点13:存储第一次then的回调结果返回值,用于下次then的参数传递,以下let x 同理 let x = onfulfilled(this.value) // 要点13.3: x 可能会是一个promise, 需要单独处理, // 并将promise2、新的返回值:x 、成功回调resolve 失败回调reject 作为参数传递 resolvePromise(promise2, x, resolve, reject) } catch (e) { // 要点13.2. 报错或抛出异常处理,直接走promise2的reject,以下同理 reject(e) } }) } // 以下逻辑同理 if (this.status === REJECTED) { setTimeout(() => { try { let x = onrejected(this.reason) resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }) } if (this.status === PENDING) { // 暂存成功回调队列 this.onfulfilledCallbacks.push(() => { setTimeout(() => { try { let x = onfulfilled(this.value) resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }) }) // 暂存失败回调队列 this.onrejectedCallbacks.push(() => { setTimeout(() => { try { let x = onrejected(this.reason) resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }) }) } }) return promise2 // 要点 12: 返回一个新的promise实例 } } // Commonjs规范导出模块 module.exports = Promise
myPromise — 值的透传
Promise 值的穿透,当一个promise连续then多次 ,并且then中没有返回任何值时,此时data会穿透值最后一个then中
test.js
//原生方法:值的穿透 演示 let p = new Promise((resolve,reject)=>{ resolve(1) // reject(2) // 同理 }) p.then().then().then(data=>{ console.log(data); // 1 }) p.then().then().then(null,err=>{ console.log(err); // 2 }) // ---------------------------------------------------------- //myPromise:基于以上几部分的实现,我们自己的promise是不支持穿透的,那么看一下演变过程,就很容易写出符合规范的透传 const Promise = require('./1.myPromise') let p1 = new Promise((resolve,reject)=>{ resolve(1) }) let p2 = new Promise((resolve,reject)=>{ reject(2) // 同理, }) // 相当于, 啥都不写时,感觉像是默认定义了一个函数,不停向下传递,去实现一下吧~ p1.then(data => data) .then(data => data) .then(data =>{ console.log(data); }) // 相当于, throw err,不停向下传递 p2.then(null,err=>{ throw err }).then(null,err=>{ console.log(err); throw err }).then(null,err=>{ console.log(err); })
myPromise.js 上面重复的代码是在是太多了,就不在赘述了,怕看着更晕了,来, 找到类中then方法定义的位置,加上下面两行代码,就可以完美实现成功及失败的数据透传
... ... ... // 在这里这里...其他都不变 then(onfulfilled, onrejected) { // onfulfilled 是函数就执行,不是函数包一层函数并直接返回数据 onfulfilled = typeof onfulfilled === 'function' ? onfulfilled : v => v; // onrejected 是函数就执行,不是函数包一层函数并直接抛出错误 onrejected = typeof onrejected === 'function' ? onrejected : err => { throw err }; ... ... ...
完美通过官方872条用例
为了测试myPromise库,必须公开一个非常小的适配器接口。可以说是promise的延迟对象defer,下文会详细介绍,各位稍安勿躁。
- 第一步:找到文件最下面。加上下面几行代码,
/** * ... * 其余不变 * ... */ // 测试自己的写的promise 是否符合a+规范 // promise的延迟对象 Promise.defer = Promise.deferred = function () { let dfd = {} dfd.promise = new Promise((resolve, reject) => { dfd.resolve = resolve; dfd.reject = reject }) return dfd; } module.exports = Promise
- 第二步:安装测试包
npm install promises-aplus-tests -g
- 第三步:进入对应目录执行
promises-aplus-tests ./1.myPromise.js
- 如果你的测试结果和我图中标注一样,那么恭喜你,如果验证不通过,肯定是有一些不一样,注意看报错信息,修正一下就好了
myPromise的延迟对象defer用法
promise是为了解决异步回调函数嵌套问题,那么可以通过promise的延迟对象来减少一层嵌套关系 模拟数据准备,准备以下两个文件,
- name.txt:文件内容是:age.txt
- age.txt:文件内容18
需求:首先通过
fs
模块读取到name中的内容(读到新的filepath),再去读取age.txt中的内容并输出
没有延迟对象的写法:
const fs = require('fs') const Promise = require('./1.myPromise') function read(filepath){ // 想要read方法可以使用then方法,需要包一层new Promise return new Promise((resolve,reject)=>{ fs.readFile(filepath,'utf8',function(err,data){ if(err) return reject(err) resolve(data) }) }) } read('./name.txt').then(data=>{ return read(data) // data = age.txt }).then(data=>{ console.log(data); // data = age.txt })
使用延迟对象的写法:
const fs = require('fs') const Promise = require('./1.myPromise') function readDefer(filepath){ let dfd = Promise.defer() // 减少一层嵌套 fs.readFile(filepath,'utf8',function(err,data){ if(err) return dfd.reject(err) dfd.resolve(data) }) return dfd.promise } readDefer('./name.txt').then(data=>{ return readDefer(data) // data = age.txt }).then(data=>{ console.log(data); // data = age.txt })
myPromise.catch
完成以上内容,就已经实现了Promise A+ 规范的全部内容,而我们常用的
catch及
finally并不属于 A+规范,同样可以实现一下,
catch是属于
实例上的方法,用于出错处理及捕获异常 演变过程:test.js
const Promise = require('./1.myPromise') new Promise((resolve, reject) => { reject('失败') }).then(data => { // 第一个then没有错误处理方法,直接会传递到第二个then中 console.log(data); }).then(null, err => { console.log(err, 'errrrrr'); // 失败 errrrrr }) // 将上述代码中null优化一下,于是就有了catch方法 new Promise((resolve, reject) => { reject('失败') }).then(data => { console.log(data); }).catch(err => { console.log(err, 'errrrrr'); // 失败 errrrrr })
实现:myPromise.js
class Promise{ // 重复代码省略 // constructor(){...} // then(){...} catch(onrejected){ // 实例的catch return this.then(null,onrejected) } } /** * 其余重复代码省略 */
myPromise.finally
finally方法是属于
实例上的方法.表示无论成功还是失败,都会执行,并且可以向下执行。理解起来有点点绕哈,建议多看几遍吧, test.js
const Promise = require('./1.myPromise') let p1 = new Promise((resolve, reject) => { setTimeout(() => { // resolve('成功') // 1 reject('失败') // 2 }, 1000) }).finally(() => { return new Promise((resolve, reject) => { setTimeout(() => { // resolve(1000) // 3 不会采用promise成功的结果,但是会等待执行 reject(9000) // 4 但是返回一个失败的promise,会走catch,相当于throw new Error }, 1000) }) }).then(data => { console.log(data); // 对应上述不同序号组合,输出结果有所不同,可自行组合实验,下方也会给大家作出总结 }).catch(e => { console.log(e, 'catch'); }) /** * 整理流程: * 组合: * 1+3:成功 + 成功 ,走then=>data 返回 1 返回的数据('成功') * 1+4:成功 + 失败 ,走then=>err 抛出 4 返回的数据(9000) * 2+3:失败 + 成功 ,走then=>err 抛出 2 返回的数据('失败') * 2+4:失败 + 失败 ,走then=>err 抛出 4 返回的数据(9000) */
实现:myPromise.js
/** * 1. finally 传递了一个方法 callback * 2. finally 方法相当于一个then,特点就是在函数中返回一个promise,并会等待这个promise的完成 * 3. Promise.resolve 又会等待 callback执行完成 */ class Promise{ // 重复代码省略 // constructor(){...} // then(){...} // catch(){...} finally(cb){ return this.then((data)=>{ // 成功 || 失败 都会执行 // Promise.resolve 目的是等待cb() 后的promise完成 // 成功时调用finally,直接传递this实例成功的数据data,finally方法本身是没有参数的 return Promise.resolve(cb()).then(()=>data) },(err)=>{ // 失败时调用finally,等待Promise.resolve(cb())的执行的结果,当cb结果为失败时,直接以失败的结果直接走catch // 而只有在Promise.resolve成功时候,才会去执行.then(()=>{throw err}),抛出this实例reject的err信息 return Promise.resolve(cb()).then(()=>{throw err}) }) } } /** * 其余重复代码省略 */
myPromise.resolve
Promise.resolve()方法会创造一个成功的promsie,属于类上的方法,通过className调用 演变过程:test.js
const Promise = require('./1.myPromise') Promise.resolve(200).then(data => { console.log(data); // 200 }) // 等价于 new Promise((resolve, reject) => { resolve(200) }).then(data => { console.log(data); // 200 })
实现:myPromise.js
constructor(executor) { /** * 其余重复无改动 */ let resolve = (value) => { // 一个promise直接resolve 另一个promise时,会等待里面的promise执行完,返回成功的执行结果 if (value instanceof Promise) { return value.then(resolve, reject) } if (this.status === PENDING) { this.value = value this.status = RESOLVED this.onfulfilledCallbacks.forEach(fn => fn()) } } let reject = (reason) => { // reject 一个promise时,不需要单独处理,失败就直接走失败的逻辑,不用处理其返回值 if (this.status === PENDING) { this.reason = reason this.status = REJECTED this.onrejectedCallbacks.forEach(fn => fn()) } } /** * 其余重复无改动 */ } static resolve(value) { return new Promise((resolve, reject) => { resolve(value) }) }
myPromise.reject
Promise.reject()方法会创造一个失败的promsie,属于类上的方法,通过className调用
演变过程:test.js
const Promise = require('./1.myPromise') Promise.reject(100).then(null,err => { console.log(err, 'errrrrr'); // 100 errrrrr }) // 等价于 new Promise((resolve, reject) => { reject(100) }).then(data=>{ console.log(data); },err => { console.log(err, 'errrrrr'); // 100 errrrrr })
实现:myPromise.js
class Promise{ /** * 其余重复无改动 */ static reject(reason) { return new Promise((resolve, reject) => { reject(reason) }) } } /** * 其余重复无改动 */
myPromise.all
Promise.all()方法用于将多个 Promise 实例,包装并返回一个新的 Promise 实例
p
p的状态由传递的多个 Promise 决定,分成两种情况。(官网是这样说的)
(1)只有所有promise实例的状态都变成
fulfilled,
p的状态才会变成
fulfilled,此时数组中promise的返回值组成一个数组,传递给
p的回调函数。
(2)只要数组的中promise有一个被
rejected,
p的状态就变成
rejected,此时第一个被
reject的实例的返回值,会传递给
p的回调函数。 test.js
const Promise = require('./1.myPromise') Promise.all([ 1, 2, 3, new Promise((resolve, reject) => { setTimeout(() => { resolve('成功') }, 1000) }), new Promise((resolve, reject) => { setTimeout(() => { resolve('成功') // 情况1 // reject('失败') // 情况2 }, 1000)}) ]).then(data => { console.log(data); // 情况1. [ 1, 2, 3, '成功', '成功' ] }).catch(err => { console.log(err); // 情况2. 失败 })
myPromise.js
class Promise{ // 在原有代码基础上,添加一个静态方法 static all(promises){ return new Promise((resolve,reject)=>{ let result = [] let times = 0 const processSuccess = (index,val)=>{ result[index] = val if(++times === promises.length){ resolve(result) } } for (let i = 0; i < promises.length; i++) { // 并发。多个请求一起执行 let p = promises[i]; if(p && typeof p.then === 'function'){ // 判断p是不是promise实例,是则继续等待p的执行结果,处理p对应的成功和失败 p.then(data=>{ processSuccess(i,data) },reject) // 如果其中一个promise失败了,直接执行失败回调,由于reject本身就是函数,故可简写 }else{ // 如果不是promise实例就直接调用成功,并存储该值 processSuccess(i,p) } } }) } }
myPromise.race
Promise.race()方法同样是将多个 Promise 实例,包装并返回一个新的 Promise 实例
p。 只要有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。 (简单理解:race 赛跑,采用最快的那一个,race方法如果其中一个完成了,其他方法还是会执行完,只是并没有采用他的结果) test.js
const Promise = require('./1.myPromise') Promise.race([ new Promise((resolve, reject) => { setTimeout(() => { resolve('成功') }, 2000) }), new Promise((resolve, reject) => { setTimeout(() => { reject('失败') }, 1000) }) ]).then(data => { console.log(data); }).catch(err => { console.log(err); // 输出:失败,resolve 2s执行,reject 1s执行,reject更快 })
myPromise.js
class Promise{ static race(promises){ return new Promise((resolve,reject)=>{ // for循环执行,只要有一个状态发生改变,就直接将该实例的返回值 返回 for (let i = 0; i < promises.length; i++) { let p = promises[i]; if(p && typeof p.then === 'function'){ p.then(data=>{ resolve(data) },reject) }else{ resolve(p) } } }) } }
myPromise终极版本
😂😂在我耐心终将耗尽之际,终于迎来了终极版
show一下myPromise全家桶
,这里终极版本,为了大家看着方便,我就把注释全都取掉了,有不理解的可以返回去对应的标题查看解说,来咯
const RESOLVED = 'RESOLVED' const REJECTED = 'REJECTED' const PENDING = 'PENDING' const resolvePromise = (promise2, x, resolve, reject) => { if (promise2 === x) { return reject(new TypeError('循环引用报错')) } if (x !== null && (typeof x === 'object' || typeof x === 'function')) { let called; try { let then = x.then if (typeof then === 'function') { then.call(x, y => { if (called) return called = true resolvePromise(promise2, y, resolve, reject) }, e => { if (called) return called = true reject(e) }) } else { resolve(x) } } catch (e) { if (called) return called = true reject(e) } } else { resolve(x) } } class Promise { constructor(executor) { this.status = PENDING this.value = undefined this.reason = undefined this.onfulfilledCallbacks = [] this.onrejectedCallbacks = [] let resolve = (value) => { if (value instanceof Promise) { return value.then(resolve, reject) } if (this.status === PENDING) { this.value = value this.status = RESOLVED this.onfulfilledCallbacks.forEach(fn => fn()) } } let reject = (reason) => { if (this.status === PENDING) { this.reason = reason this.status = REJECTED this.onrejectedCallbacks.forEach(fn => fn()) } } try { executor(resolve, reject) } catch (e) { reject(e) } } then(onfulfilled, onrejected) { onfulfilled = typeof onfulfilled === 'function' ? onfulfilled : v => v; onrejected = typeof onrejected === 'function' ? onrejected : err => { throw err }; let promise2 = new Promise((resolve, reject) => { if (this.status === RESOLVED) { setTimeout(() => { try { let x = onfulfilled(this.value) resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }) } if (this.status === REJECTED) { setTimeout(() => { try { let x = onrejected(this.reason) resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }) } if (this.status === PENDING) { this.onfulfilledCallbacks.push(() => { setTimeout(() => { try { let x = onfulfilled(this.value) resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }) }) this.onrejectedCallbacks.push(() => { setTimeout(() => { try { let x = onrejected(this.reason) resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }) }) } }) return promise2 } catch (onrejected) { return this.then(null, onrejected) } finally(cb) { return this.then( (data) => { return Promise.resolve(cb()).then(() => data) }, (err) => { return Promise.resolve(cb()).then(() => { throw err }) }) } static resolve(value) { return new Promise((resolve, reject) => { resolve(value) }) } static reject(reason) { return new Promise((resolve, reject) => { reject(reason) }) } static all(promises) { return new Promise((resolve, reject) => { let result = [] let times = 0 const processSuccess = (index, val) => { result[index] = val if (++times === promises.length) { resolve(result) } } for (let i = 0; i < promises.length; i++) { let p = promises[i]; if (p && typeof p.then === 'function') { p.then(data => { processSuccess(i, data) }, reject) } else { processSuccess(i, p) } } }) } static race(promises) { return new Promise((resolve, reject) => { for (let i = 0; i < promises.length; i++) { let p = promises[i]; if (p && typeof p.then === 'function') { p.then(data => { resolve(data) }, reject) } else { resolve(p) } } }) } } Promise.defer = Promise.deferred = function () { let dfd = {} dfd.promise = new Promise((resolve, reject) => { dfd.resolve = resolve; dfd.reject = reject }) return dfd; } module.exports = Promise
🧡🧡🧡Click Me🧡🧡🧡
既然你都看到这了,想必你肯定是感兴趣啦,希望这篇文章对你更加了解Promise有所帮助,后续工作之余还会分享更多实用的技巧和源码分析,点个赞加个关注再走呗
- 使用es6的class实现显示本周、上周、下周的日期
- 使用ES6的Promise完美解决回调地狱
- 使用ES6的Promise完美解决回调地狱
- 使用ES6的Promise完美解决回调地狱
- es6 类class的使用以及promise(异步请求)基础
- 通过使用模拟实现Promise
- 使用ES6的Promise完美解决回调地狱
- 在C++中使用事件回调机制(通过Observer模式、函数指针等实现)
- 通过CSS3实现不使用图片创建气泡
- .NET1.1下,使用C#自动生成Word2003文档(通过操作COM组件实现)
- 使用CSS完美实现垂直居中的方法
- 第三节--通过Intent实现Activity的数据传送及Meun的创建和使用
- JAVA上加密算法的实现用例MD5/SHA1,DSA,DESede/DES,Diffie-Hellman的使用(转)
- 使用 UML 进行有效的业务建模: 描述业务用例和实现
- 使用AspNetPager分页控件、分页存储过程及用户控件基类实现的完美分页功能
- MF中使用GPRS:如何通过一个串口终端实现GPRS Modem拨号上网
- 使用C#实现通过网络发送和播放麦克风的声音
- spring security 2中使用通过自定义过滤器实现多登录页面
- 通过patch实现生成使用补丁
- ASP.NET jQuery 食谱11 (通过使用jQuery validation插件简单实现用户登录页面验证功能)