当前位置:网站首页>【ES6闯关】Promise堪比原生的自定义封装(万字)
【ES6闯关】Promise堪比原生的自定义封装(万字)
2022-06-24 07:28:00 【codeMak1r.】
在本篇文章中,你可以学习到:
Promise对象的底层实现原理
Promise对象实现自定义封装
同步与异步
回调函数
函数作用域中的this指向问题
trycatch捕获错误
JavaScript底层实现思想🤩如果能够跟着文章思路一起敲代码的话,我相信你也能封装一个自己的promise
封装的promise源码在文章结尾
坚持创作️,一起学习,码出未来!
文章目录
- 前言
- 1、promise自定义封装--初始结构搭建
- 2、promise自定义封装--resolve与reject结构搭建
- 3、promise自定义封装--resolve和reject代码实现
- 4、promise自定义封装--throw抛出异常改变状态
- 5、promise自定义封装--Promise对象状态只能修改一次
- 6、promise自定义封装--then方法执行回调
- 7、promise自定义封装--异步任务回调的执行
- 8、promise自定义封装--指定多个回调的实现
- 9、promise自定义封装--同步then方法的返回结果
- 10、promise自定义封装--异步then方法的返回结果
- 11、promise自定义封装--then方法完善与优化
- 12、promise自定义封装--catch方法--异常穿透与值传递
- 🥤Promise——API
- 13、promise自定义封装--resolve方法封装
- 14、promise自定义封装--reject方法封装
- 15、promise自定义封装--all方法封装
- 16、promise自定义封装--race方法封装
- 17、promise自定义封装--then方法回调的异步执行
- 18、promise自定义封装--class版本的实现
- 写在最后
前言
之前我们已经对Promise对象有了一定的了解
JavaScript–ES6【Promise】对象详解
JavaScript–【Promise】详解Promise_API
那么这篇文章呢,我将带大家以闯关模式,一关关地自定义实现一个自己的【promise】
也就是【手撕Promise–Promise的自定义封装】
让我们来一起看看吧~
你的支持将会成为我创作的最大动力
关注点赞收藏
1、promise自定义封装–初始结构搭建
html:
<head>
<title>Promise--自定义封装</title>
<!-- 引入自定义的promise.js文件 -->
<script src="./promise.js"></script>
</head>
<body>
<script> let p = new Promise((resolve,reject) => {
resolve('OK') }) p.then(value => {
console.log(value) }, reason => {
console.log(reason) }) </script>
</body>
在
prmoise.js中创建一个函数为function Promise();在html中引入这个promise.js文件,这样的话,当我们在使用new Promise()时,创建的实例对象就是我们自定义的这个function Promise()的实例对象。而不是js原生中那个Promise对象。
原因是,我们创建了一个自己的Promise函数,覆盖了js原生里的那个Promise对象。
promise.js:
// 声明构造函数
function Promise() {
}
// 添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
}
2、promise自定义封装–resolve与reject结构搭建
promise.js:
// 声明构造函数
function Promise(executor) {
// 声明resolve和reject函数
function resolve(resolveResult) {
}
function reject(rejectResult) {
}
// 执行器函数executor在内部是同步调用的
executor(resolve, reject);
}
// 添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
}
3、promise自定义封装–resolve和reject代码实现
分析:resolve()函数执行有什么样的效果?对Promise对象有什么影响?
【=分割线=】
在上一篇文章我们学习到,promise对象身上有两个属性:
【PromiseState】和【PromiseResult】
得出:
resolve()函数的执行,
- 会使promise对象的状态【PromiseState】发生改变,【pending => resolved/fulfilled】(代表成功)
- 还可以设置promise对象成功的结果【PromiseResult】=> resolve(‘OK’) 成功的结果为。
我们先预设好promise对象实例身上的属性:
this.PromiseState = 'pending';
this.PromiseResult = null;
resolve函数实现:
// 声明resolve函数
resolve = (data) => {
// 1. 修改对象的状态(promiseState)
this.PromiseState = 'fulfilled' // resolved
// 2. 设置对象结果值(promiseResult)
this.PromiseResult = data
}
️注意:
在这里我们需要使用箭头函数来解决this指向的问题。
或者我们可以先把this保存下来:
const self = this;
self.PromiseState = 'fulfilled';这种方法也是可以的。
reject()函数与resolve()函数一样:
// 声明reject函数
reject = (data) => {
// 1. 修改对象的状态(promiseState)
this.PromiseState = 'rejected'
// 2. 设置对象结果值(promiseResult)
this.PromiseResult = data
}
4、promise自定义封装–throw抛出异常改变状态
promise对象状态的改变只有三种方式:
resolve(),reject()以及throw抛出异常。
其中throw抛出异常后,状态(PromiseState)【penging => rejected】
我们先预设一个promise实例:
<script> let p = new Promise((resolve, reject) => {
// 抛出异常 throw "error"; }) console.log(p) </script>
在promise.js中使用【 t r y c a t c h trycatch trycatch】方法处理抛出异常:
// 声明构造函数
function Promise(executor) {
// 添加属性
this.PromiseState = 'pending';
this.PromiseResult = null;
// 声明resolve和reject函数
resolve = (data) => {
// 1. 修改对象的状态(promiseState)
this.PromiseState = 'fulfilled' // resolved
// 2. 设置对象结果值(promiseResult)
this.PromiseResult = data
}
reject = (data) => {
// 1. 修改对象的状态(promiseState)
this.PromiseState = 'rejected'
// 2. 设置对象结果值(promiseResult)
this.PromiseResult = data
}
try {
// 执行器函数executor在内部是同步调用的
executor(resolve, reject);
} catch (error) {
// 修改promise对象的状态为失败
reject(error)
}
}
// 添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
}
5、promise自定义封装–Promise对象状态只能修改一次
我们只需要在reject()函数以及reject()函数更改状态之前,对当前的【PromiseState】进行判断即可;
若PromiseState为【pending】,则说明状态还没有被修改过;
若PromiseState不为【pending】,则说明状态已经被修改过,不再允许修改。
// 声明resolve和reject函数
resolve = (data) => {
// 判断状态是否已经被更改
if (this.PromiseState !== 'pending') return
// 1. 修改对象的状态(promiseState)
this.PromiseState = 'fulfilled' // resolved
// 2. 设置对象结果值(promiseResult)
this.PromiseResult = data
}
reject = (data) => {
if (this.PromiseState !== 'pending') return
// 1. 修改对象的状态(promiseState)
this.PromiseState = 'rejected'
// 2. 设置对象结果值(promiseResult)
this.PromiseResult = data
}
6、promise自定义封装–then方法执行回调
promise.js实现then方法
// 添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
// 调用回调函数
if (this.PromiseState === 'fulfilled') {
onResolved(this.PromiseResult)
}
if (this.PromiseState === 'rejected') {
onRejected(this.PromiseResult)
}
}
html
<script> let p = new Promise((resolve, reject) => {
resolve('OK') }) console.log(p) p.then(value => {
console.log(value) }, reason => {
console.warn(reason) }) </script>
我们知道then方法第一个实参是promise成功时的回调,第二个实参是失败时的回调;
onResolved作为then方法第一个行参,当状态为成功时调用;
onRejected作为then方法第二个行参,当状态为失败时调用。
思考️:
为什么可以在then方法内部直接用this.PromiseState做判断?
因为这个then方法是Promise实例
p调用的(p.then),所以这个then方法的内部的this隐式指向p这个实例。
谁调用的,this就指向谁。
【this.PromiseState】指的就是p这个实例自身的PromiseState属性。
7、promise自定义封装–异步任务回调的执行
我们先来new一个promise实例:
<script> let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('OK') }, 1000) }) p.then(value => {
console.log(value) }, reason => {
console.warn(reason) }) </script>
打开控制台,等待一秒成功打印出。
现在我们引入自己自定义的promise.js:
<head>
<script src="./promise.js"></script>
</head>
promise.js :
// 声明构造函数
function Promise(executor) {
this.PromiseState = 'pending';
this.PromiseResult = null;
resolve = (data) => {
if (this.PromiseState !== 'pending') return
this.PromiseState = 'fulfilled' // resolved
this.PromiseResult = data
}
reject = (data) => {
if (this.PromiseState !== 'pending') return
this.PromiseState = 'rejected'
this.PromiseResult = data
}
try {
// 执行器函数executor在内部是同步调用的
executor(resolve, reject);
} catch (error) {
// 修改promise对象的状态为失败
reject(error)
}
}
// 添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
if (this.PromiseState === 'fulfilled') {
onResolved(this.PromiseResult)
}
if (this.PromiseState === 'rejected') {
onRejected(this.PromiseResult)
}
}
发现打印台并没有像我预料的那样,打印出。
分析:
在p实例创建完成时,进入【setTimeout】函数,resolve()进入异步队列;
但是此时,同步队列并不会因此等待;
同步队列向下执行直到调用then方法(p.then)
此时promise状态并没有发生改变,依然是pending;
而我们自己声明的then方法内部并没有对状态pending做任何判断;
(自定义的then仅当状态为fulfilled以及rejected时有反应。)
先声明一个属性变量,本质是一个对象:
this.callback = {
}
在then方法中再对pending状态做判断:
// 判断pending状态
if (this.PromiseState === 'pending') {
// 保存回调函数
this.callback = {
onResolved: onResolved,
onRejected: onRejected
}
}
如果状态为pending,则将回调函数先保存下来,等到异步任务执行完毕,也就是状态改变之后再调用then方法。
// 声明resolve和reject函数
resolve = (data) => {
if (this.PromiseState !== 'pending') return
this.PromiseState = 'fulfilled' // resolved
this.PromiseResult = data
// 调用成功的回调
if (this.callback.onResolved) {
this.callback.onResolved(data)
}
}
reject = (data) => {
if (this.PromiseState !== 'pending') return
this.PromiseState = 'rejected'
this.PromiseResult = data
// 调用失败的回调
if (this.callback.onRejected) {
this.callback.onRejected(data)
}
}
如果
this.callback这个对象上存在onResolved属性,说明resolve()函数进入了异步队列,调用then方法时promise对象还处于【pending】状态。那么我们就调用
this.callback.onResolved(data),在状态改变之后重新调用then方法中的onResolved.
【onRejected】同理。
8、promise自定义封装–指定多个回调的实现
我们知道,在原生JS中的Prmoise对象实例上,无论放多少个【then】回调都是可以执行的;
但是在我们这个自定义封装的Promise中,后面的【then】会覆盖前一个【then】
原因是:
在后一个【then】方法声明时,Promise的状态依然是【pending】;
此时再次进行保存回调的操作:
this.callback = { onResolved: onResolved, onRejected: onRejected; }此时,前面所有的then方法都被最后一个then方法覆盖了,保存回调中保存的永远都是最后一个then方法。
所以:
我们应该换一个方式保存回调;
// 判断pending状态 if (this.PromiseState === 'pending') { // 保存回调函数 this.callbacks.push({ onResolved: onResolved, onRejected: onRejected }) }
将callback由对象换成数组,每次then方法的回调都会通过数组的push方法将每一个then方法push进callbacks这个数组中。
而callbacks变成了数组之后,调用成功的回调当然也需要做出改变:
// 这是之前调用成功的回调
if (this.callback.onResolved) {
this.callback.onResolved(data)
}
// 这是现在调用成功的回调
this.callbacks.forEach(item => {
item.onResolved(data)
})
失败时的回调【onRejected】同理。
9、promise自定义封装–同步then方法的返回结果
Promise同步任务修改状态 - -> then方法返回的结果
我们回顾一下:
then方法的返回结果是由then方法指定的回调内部的返回结果决定的;
图中这个回调内部没有指定返回值(没有return);
那么这个回调将返回默认的【undefined】;
【undefined】并不是一个promise类型的对象,
所以这个then方法返回的结果是:
Promise对象,状态【PromiseState】为成功;
值【PromiseResult】为undefined。
回调的返回值 then的返回值 非Promise类型 状态:成功;值:由回调的返回值决定; 例如:返回undefined 状态:成功;值:undefined Promise类型 状态:由回调内部的Promise的状态决定;
值:由回调内部的Promise的值决定例如:回调内部Promise状态为成功,值为Success 状态 :成功;值:Success
但我们自定义封装的这个Promise,目前为止,then方法的返回结果并不是一个Promise对象;
而是undefined。
这是因为,我们在定义then方法时,并没有声明返回值,所以这个then方法的返回值是undefined。
// then方法的代码
Promise.prototype.then = function (onResolved, onRejected) {
// 调用回调函数
if (this.PromiseState === 'fulfilled') {
onResolved(this.PromiseResult)
}
if (this.PromiseState === 'rejected') {
onRejected(this.PromiseResult)
}
// 判断pending状态
if (this.PromiseState === 'pending') {
// 保存回调函数
this.callbacks.push({
onResolved: onResolved,
onRejected: onRejected
})
}
}
所以我们应该修改这段代码,让then方法返回一个Promise类型的对象:
// 添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
return new Promise((resolve, reject) => {
// 调用回调函数
if (this.PromiseState === 'fulfilled') {
// 获取回调函数的执行结果
let result = onResolved(this.PromiseResult)
if (result instanceof Promise) {
// 如果then指定的回调内部是一个Promise类型的对象
result.then(value => {
resolve(value)
}, reason => {
reject(reason)
})
} else {
// 如果then指定的回调内部不是Promise类型的对象,
// 则状态为成功,值为回调函数的执行结果,也就是前面保存的result
resolve(result)
}
}
if (this.PromiseState === 'rejected') {
onRejected(this.PromiseResult)
}
// 判断pending状态
if (this.PromiseState === 'pending') {
// 保存回调函数
this.callbacks.push({
onResolved: onResolved,
onRejected: onRejected
})
}
})
}

10、promise自定义封装–异步then方法的返回结果
如图,若是异步修改状态,我们自定义封装的【Promise】
then方法返回的Promise对象状态为pending;
与原生JS中的Promise存在差异,所以我们要进行修改。
// 判断pending状态
if (this.PromiseState === 'pending') {
// 保存回调函数
this.callbacks.push({
onResolved: () => {
// 执行成功回调函数
let result = onResolved(this.PromiseResult)
if (result instanceof Promise) {
result.then(value => {
resolve(value)
}, reason => {
reject(reason)
})
} else {
resolve(result)
}
},
onRejected: () => {
let result = onRejected(this.PromiseResult)
if (result instanceof Promise) {
result.then(value => {
resolve(value)
}, reason => {
reject(reason)
})
} else {
resolve(result)
}
}
})
}
当异步执行时,P这个实例调用then方法时,Promise对象的状态依旧为【pending】;
那么,我们就先将回调函数保存在callbacks这个数组身上;
当状态改变时(比如setTimeout执行时机一到,状态变为成功)
setTimeout(() => { resolve('OK') }, 1000)状态改变时,再重新调用then方法之前保存的回调函数:
resolve = (data) => { // 判断状态是否已经被更改 if (this.PromiseState !== 'pending') return // 1. 修改对象的状态(promiseState) this.PromiseState = 'fulfilled' // resolved // 2. 设置对象结果值(promiseResult) this.PromiseResult = data // 调用成功的回调 this.callbacks.forEach(item => { item.onResolved() }) }若抛出异常,可以用try catch解决:
onRejected: () => { try { let result = onRejected(this.PromiseResult) if (result instanceof Promise) { result.then(value => { resolve(value) }, reason => { reject(reason) }) } else { resolve(result) } } catch (error) { reject(error) } }
11、promise自定义封装–then方法完善与优化
我们可以看到,当状态为【fulfilled】以及【pending】时,我们都对then方法返回的Promise对象进行了一系列的设置;
但是若P实例状态为失败时,我们并没有改变then方法返回的Promise对象的任何东西;
所以我们还需要在状态为失败时进行设置:
if (this.PromiseState === 'rejected') { try { let result = onRejected(this.PromiseResult) if (result instanceof Promise) { result.then(value => { resolve(value) }, reason => { reject(reason) }) } else { resolve(result) } } catch (error) { reject(error) } }
还可以看出,不同判断体中的代码相似程度非常高,我们可以对代码进行一些优化,以达到代码复用的目的:
封装函数
Promise.prototype.then = function (onResolved, onRejected) {
const self = this
return new Promise((resolve, reject) => {
function callback(type) {
try {
// 获取回调函数的执行结果
let result = type(self.PromiseResult)
if (result instanceof Promise) {
// 如果then指定的回调内部是一个Promise类型的对象
result.then(value => {
resolve(value)
}, reason => {
reject(reason)
})
} else {
// 如果then指定的回调内部不是Promise类型的对象,
//则状态为成功,值为回调函数的执行结果,也就是前面保存的result
resolve(result)
}
} catch (error) {
reject(error)
}
}
// 调用回调函数
if (this.PromiseState === 'fulfilled') {
callback(onResolved)
}
if (this.PromiseState === 'rejected') {
callback(onRejected)
}
// 判断pending状态
if (this.PromiseState === 'pending') {
// 保存回调函数
this.callbacks.push({
onResolved: () => {
callback(onResolved)
},
onRejected: () => {
callback(onRejected)
}
})
}
})
}
封装一个函数function callback(type)
在成功时调用callback(onResolved);在失败时调用callback(onRejected);
12、promise自定义封装–catch方法–异常穿透与值传递
在自定义封装的Promise对象上添加catch方法:
// 添加catch方法 Promise.prototype.catch = function (onRejected) { return this.then(undefined, onRejected) }catch方法中直接调用了已经预设好的then方法,传递的第一个参数为undefined,第二个参数为onRejected;
此时,then方法第一个成功的回调不会执行;
直接接受参数执行onRejected第二个失败的回调。
此时,我们可以正常使用p.catch()以及p.then()方法,
但是,在使用p.then().catch()方法时,碰到了问题:
p.then().catch()方法,在原生的promise中,支持我们then方法的第二个参数选择不传;
例如:
p.then(value => { console.log(value) }).catch(reason => { console.warn(reason) })但是在我们自定义的promise身上,then第二个参数不传会被认定为是【undefined】;
这样会导致一些错误*️;
所以我们还需要对then方法的第二个参数【onRejected】进行判断:
// 判断回调函数参数 if (typeof onRejected !== 'function') { onRejected = reason => { throw reason; } }如果没传第二个参数,就将onRejected定义为一个箭头函数,并且抛出异常;
这样就对,不传第二个参数这一情况做了一个预先的设置,
不传第二个参数 ==> 默认抛出异常
这一点在异常穿透上很有用
异常穿透
let p = new Promise((resolve, reject) => {
setTimeout(() => {
reject('888')
}, 1000)
})
p.then(value => {
// 不传第二个参数,默认抛出异常
console.log('111')
}).then(value => {
// 不传第二个参数,默认抛出异常
console.log('222')
}).then(value => {
// 不传第二个参数,默认抛出异常
console.log('333')
}).catch(reason => {
console.warn(reason) // 处理抛出的异常
})
值传递
在原生的promise身上,拥有值传递的特性;
也就是说,then方法的第一个参数也可以不传:
p.then().then(value => { console.log('222') }).then(value => { console.log('333') }).catch(reason => { console.warn(reason) })这里第一个then方法的两个参数都没有传递,但是依然可以运行;
那么在我们自定义封装的Promise身上,就没有这个特性了。
我们需要对第一个参数进行一些判断:
if (typeof onResolved !== 'function') { onResolved = value => value }如果then方法没有指定参数,就默认指定一个参数,以完成值传递。
这样的效果,就与原生的promise的效果是一模一样的了~
🥤Promise——API
接下来将展开Promise「 API 」的自定义封装,关于Promise【API】一些本文的前置知识
13、promise自定义封装–resolve方法封装
// 添加resolve方法
Promise.resolve = function (value) {
// 返回promise对象
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(value => {
resolve(value)
}, reason => {
reject(reason)
})
} else {
resolve(value)
}
})
}
注意️:resolve()方法并不是在Promise对象实例身上,而是在Promise对象自己身上。
resolve()方法的目的是为了快速的创建一个Promise对象。
调用:
const p = Promise.resolve('OK') console.log(p)这里的p就是一个Promise实例对象。
14、promise自定义封装–reject方法封装
// 添加reject方法
Promise.reject = function (reason) {
return new Promise((resolve, reject) => {
reject(reason)
})
}
注意️:与resolve()方法同理,reject()并不是在Promise对象实例身上,而是在Promise对象自己身上。
reject()方法的目的是为了快速的创建一个Promise对象。
调用:
const p = Promise.reject('Error') console.log(p)这里的p就是一个失败的Promise实例对象。
15、promise自定义封装–all方法封装
// 添加all方法
Promise.all = function (promises) {
return new Promise((resolve, reject) => {
// 声明变量
let count = 0;
// 保存成功结果的数组
let arr = [];
// 遍历
for (let i = 0; i < promises.length; i++) {
promises[i].then(value => {
// 得知对象的状态是成功的
count++;
// 将当前promise对象成功的结果存入到数组中
arr[i] = value;
if (count === promises.length) {
// 每个promise对象都成功
resolve(arr)
}
}, reason => {
reject(reason)
})
}
})
}
注意️:
all()方法的特性是:
传入的所有promise对象都成功,all方法返回的promise对象才为成功,
且成功的值为所有传入的promise对象成功的值组成的数组。
=【分割线】=
只要传入的promise对象中有一个是失败,那么all方法返回的promise对象的结果为失败;
且失败的值为传入的那个失败的promise的结果的值。
调用all()方法:
let p1 = new Promise((resolve, reject) => { resolve('OK') }) let p2 = Promise.resolve('Success') let p3 = Promise.resolve('Oh Yeah') let result = Promise.all([p1, p2, p3]) console.log(result)result打印结果为成功的Promise对象,值为[‘OK’,‘Sueccess’,‘Oh yeah’]数组。
16、promise自定义封装–race方法封装
️
race()方法的特性是:
传入的promise对象组成的数组作为参数,数组中所有的promise对象,
谁先改变状态,race()方法返回的promise的状态就是谁。
比如:Promise.race([p1, p2, p3]) 其中,p1, p2, p3均为promise类型的对象
若p1这个promise先改变状态,且状态为失败;
那么,这个race()方法返回的结果为一个promise对象,状态也为失败;
race()方法可以理解为【竞速】,也就是传入的多个promise对象之间竞速,谁先改变状态,谁就决定了race()方法返回的那个promise。
// 添加race方法
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(value => {
resolve(value)
}, reason => {
reject(reason)
})
}
})
}
使用Promise.race()
let p1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('OK') }, 1000) }) let p2 = Promise.resolve('Success') let p3 = Promise.resolve('Oh Yeah') let result = Promise.race([p1, p2, p3]) console.log(result)result打印结果为:成功的promise对象,成功的值为’Success’
17、promise自定义封装–then方法回调的异步执行
let p1 = new Promise((resolve, reject) => {
resolve('OK')
console.log('111')
})
p1.then(value => {
console.log('222')
})
console.log('333')
正常情况下,原生Promise中的then方法是异步执行的;
所以输出顺序应该是:
111
333
222
原因是,then方法内部是异步执行的,只有等同步代码执行完毕后,异步的222才会输出。
但是,使用我们自定义封装的promise后,输出顺序是:
111
222
333
原因是我们没有对then方法指定的回调设置异步,所以需要做一些改进。
在声明的resolve与reject函数中,为调用回调设置异步:
resolve = (data) => {
// 判断状态是否已经被更改
if (this.PromiseState !== 'pending') return
// 1. 修改对象的状态(promiseState)
this.PromiseState = 'fulfilled' // resolved
// 2. 设置对象结果值(promiseResult)
this.PromiseResult = data
// 调用成功的回调
setTimeout(() => {
this.callbacks.forEach(item => {
item.onResolved()
})
})
}
reject = (data) => {
if (this.PromiseState !== 'pending') return
// 1. 修改对象的状态(promiseState)
this.PromiseState = 'rejected'
// 2. 设置对象结果值(promiseResult)
this.PromiseResult = data
// 调用失败的回调
setTimeout(() => {
this.callbacks.forEach(item => {
item.onResolved()
})
})
}
在自定义的then方法中,调用回调设置异步:
// 调用回调函数
if (this.PromiseState === 'fulfilled') {
setTimeout(() => {
callback(onResolved)
})
}
if (this.PromiseState === 'rejected') {
setTimeout(() => {
callback(onRejected)
})
}
这样一来,我们自定义的这个then方法就与原生Promise的then方法在表现上是一样的了。
控制台输出:
111
333
222
18、promise自定义封装–class版本的实现
那么到这里呢,我们自定义封装的这个Promise一些相关的功能呢都已经完成了。
接下来,我们将这个Promise封装为一个class类。
class Promise {
// 构造方法
constructor(executor) {
// 添加属性
this.PromiseState = 'pending';
this.PromiseResult = null;
// 声明属性
this.callbacks = [];
// 保存实例对象的this
const self = this;
// 声明resolve和reject函数
function resolve(data) {
// 判断状态是否已经被更改
if (self.PromiseState !== 'pending') return
// 1. 修改对象的状态(promiseState)
self.PromiseState = 'fulfilled' // resolved
// 2. 设置对象结果值(promiseResult)
self.PromiseResult = data
// 调用成功的回调
setTimeout(() => {
self.callbacks.forEach(item => {
item.onResolved()
})
})
}
function reject(data) {
if (self.PromiseState !== 'pending') return
// 1. 修改对象的状态(promiseState)
self.PromiseState = 'rejected'
// 2. 设置对象结果值(promiseResult)
self.PromiseResult = data
// 调用失败的回调
setTimeout(() => {
self.callbacks.forEach(item => {
item.onRejected()
})
})
}
try {
// 执行器函数executor在内部是同步调用的
executor(resolve, reject);
} catch (error) {
// 修改promise对象的状态为失败
reject(error)
}
}
// 添加then方法
then(onResolved, onRejected) {
// 判断回调函数参数
if (typeof onRejected !== 'function') {
onRejected = reason => {
throw reason;
}
}
if (typeof onResolved !== 'function') {
onResolved = value => value
}
const self = this
return new Promise((resolve, reject) => {
function callback(type) {
try {
// 获取回调函数的执行结果
let result = type(self.PromiseResult)
if (result instanceof Promise) {
// 如果then指定的回调内部是一个Promise类型的对象
result.then(value => {
resolve(value)
}, reason => {
reject(reason)
})
} else {
// 如果then指定的回调内部不是Promise类型的对象,
//则状态为成功,值为回调函数的执行结果,也就是前面保存的result
resolve(result)
}
} catch (error) {
reject(error)
}
}
// 调用回调函数
if (this.PromiseState === 'fulfilled') {
setTimeout(() => {
callback(onResolved)
})
}
if (this.PromiseState === 'rejected') {
setTimeout(() => {
callback(onRejected)
})
}
// 判断pending状态
if (this.PromiseState === 'pending') {
// 保存回调函数
this.callbacks.push({
onResolved: () => {
callback(onResolved)
},
onRejected: () => {
callback(onRejected)
}
})
}
})
}
// 添加catch方法
catch(onRejected) {
return this.then(undefined, onRejected);
}
// 添加resolve方法
static resolve(value) {
// 返回promise对象
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(value => {
resolve(value)
}, reason => {
reject(reason)
})
} else {
resolve(value)
}
})
}
// 添加reject方法
static reject(reason) {
return new Promise((resolve, reject) => {
reject(reason)
})
}
// 添加all方法
static all(promises) {
return new Promise((resolve, reject) => {
// 声明变量
let count = 0;
// 保存成功结果的数组
let arr = [];
// 遍历
for (let i = 0; i < promises.length; i++) {
promises[i].then(value => {
// 得知对象的状态是成功的
count++;
// 将当前promise对象成功的结果存入到数组中
arr[i] = value;
if (count === promises.length) {
// 每个promise对象都成功
resolve(arr)
}
}, reason => {
reject(reason)
})
}
})
}
// 添加race方法
static race(promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(value => {
resolve(value)
}, reason => {
reject(reason)
})
}
})
}
}

写在最后
最后,我们完成封装了一个堪比原生的Promise对象~
完结撒花
全文共18470字,1323行,耗时数天时间
原创不易,你的支持将会成为我创作的动力
关注点赞收藏
码出未来!
边栏推荐
- Data middle office: the data middle office practice scheme of Minsheng Bank
- Data midrange: analysis of full stack technical architecture of data midrange, with industry solutions
- 216. 组合总和 III-枚举法
- MySQL data (Linux Environment) scheduled backup
- 4275. Dijkstra sequence
- 所说的Get post:请求的区别,你真的知道了吗??????
- leetcode——错误的集合
- Camera projection matrix calculation
- [MySQL from introduction to mastery] [advanced part] (I) character set modification and underlying principle
- Opencv daily function structure analysis and shape descriptor (7) finding polygon (contour) / rotating rectangle intersection
猜你喜欢

【LeetCode】415. String addition

China chip Unicorn Corporation

YOLOX backbone——CSPDarknet的实现
![[noi Simulation Competition] geiguo and time chicken (structure)](/img/4c/ed1b5bc2bed653c49b8b7922ce1674.png)
[noi Simulation Competition] geiguo and time chicken (structure)

“不平凡的代理初始值设定不受支持”,出现的原因及解决方法

On the routing tree of gin

【LeetCode】415. 字符串相加

Transplantation of xuantie e906 -- fanwai 0: Construction of xuantie c906 simulation environment

Matlab camera calibrator camera calibration

Wan Weiwei, a researcher from Osaka University, Japan, introduced the rapid integration method and application of robot based on WRS system
随机推荐
MySQL data (Linux Environment) scheduled backup
Wan Weiwei, a researcher from Osaka University, Japan, introduced the rapid integration method and application of robot based on WRS system
陆奇:我现在最看好这四大技术趋势
Alibaba Senior Software Testing Engineer recommends testers to learn -- Introduction to security testing
小程序云数据,数据请求一个集合数据的方法
[Niuke] length of the last word of HJ1 string
On the routing tree of gin
十二、所有功能实现效果演示
常用表情符号
110. balanced binary tree recursive method
【牛客】把字符串转换成整数
Common emoticons
4275. Dijkstra sequence
数组相向指针系列
【LeetCode】415. String addition
数据中台:国内大厂中台建设架构集锦
Remote connection of raspberry pie without display by VNC viewer
Mysql数据(Liunx环境)定时备份
Data middle office: middle office practice and summary
What is graph neural network? Figure what is the use of neural networks?



