Promise函数自定义封装详解(一)
Promise的自定义封装(一)
大家好,今天我们来学习一下手写promise函数的源码,完成对promise函数功能和方法的封装。
首先,我们需要明白什么是promise函数,以及它的作用,内置的API等。
Promise函数的基本理解
简单来说,promise函数是为了解决异步回调时的一些问题,更准确来说是为了解决我们在开发中,经常会面临的“回调地狱”所给开发者带来的困扰。promise可以被理解成一个方案,来有助于我们快速规避这些麻烦,从而提高我们的开发效率。
我们知道一个promise函数的状态必然处于以下几种状态中的一个:
- 待定(pending) :初始状态,既没有被兑现,也没有被拒绝。
- 已兑现(fulfilled) :意味着操作成功完成。
- 已拒绝(rejected) :意味着操作失败。
promise内置的几种方法
既然我们知道了promise的作用之后,我们就来谈谈promise函数所内置的几个API,也就是方法,这些方法在我们往后的学习和工作当中会被反复的使用,因此要熟悉这些API能实现的功能变的尤为重要:
- resolve:promise构造函数上挂载或在内部定义的方法,表示一个“成功”时的状态,且此状态一旦生成就不可逆,此过程也称为“敲定”了这个状态。
- reject:promise构造函数上挂载或在内部定义的方法,表示一个“失败”时的状态,且此状态一旦生成就不可逆,此过程也称为“敲定”了这个状态。
- then:promise.then方法返回的结果也是一个promise函数,准确来说是一个对象,这个对象中有then方法返回的promise对象及其所处的状态和结果值等,因此这个新对象也可以使用promise所内置的方法。
- catch:catch在promise中经常用来快速捕捉异常,例如捕捉throw抛错时而导致的非正常状态,在自定义封装中我们用try …catch来搭配使用,catch返回值是一个失败的promise对象。
- all: promise中all方法的参数接受一个数组,这个数组的成员要满足都为promise对象。如果所有的promise对象状态都为“fulfilled”,也就是成功,all方法返回一个状态也为成功的promise对象,此对象内部的结果值为此成功的数组。若有一个promise成员的状态为失败,那么all方法就会返回一个失败的promise对象,其状态为”rejected”,其内部结果值为这个数组中失败的promise函数的结果值。
- race: promise中race方法的参数接受一个数组,这个数组的成员要满足都为promise对象,race方法返回一个promise对象,这个对象的状态由数组中第一个状态改变的promise函数决定,且两个对象的状态保持一致,且其结果值为数组中第一个状态改变的promise函数的结果值。
Promise函数自定义封装代码实现
1.html文件和js文件的基本配置
第一步,我们要创建一个html页面和一个js文件,并将这个js文件引入这个html页面中。此外我们需要在js文中定义一个promise构造函数,来实现对js原来内置promise函数的覆盖,如图
2.创建一个promise实例对象
第二步,我们要在html里的script模块中创建一个promise的实例化对象,并在此对象的参数中写入执行器函数(exector),并声明一个变量p来接收这个promise函数整体的返回结果,除此之外,我们可以在这个函数体内部调用一个resolve方法,供后期使用。如图:
此时我们打印p的结果,如图显示
这说明我们创建promise函数实例化成功,p内部的constructor函数成功指向定义的promise函数。实参executor(箭头函数)成功传入js文件中的promise的形参,只不过promise函数体内没有任何代码,所以没有其他执行结果。
3.promise构造函数内部基本配置
第三步,我们要在这个定义的promise函数中添加这么几个部分:
1.在promise构造函数内部设置默认的状态值pending和结果值null
2.把构造函数内部的this指向赋值给变量self,传入到下面的函数
3.设置一个空数组callbacks,供后期执行异步操作时使用
4.设置一个resolve函数,在其内部设置实例对象p成功时的状态值“fulfilled”和结果值data
5.设置一个reject函数,在其内部设置实例对象p失败时的状态值“rejected”和结果值data
6.利用try…catch来执行传来的exector函数并捕捉可能存在的异常
具体代码如下:
function Promise(exector) {
// 设置默认状态和默认值
this.PromiseState = 'pending'
this.PromiseResult = null
// 设置一个空数组,异步时调用
this.callbacks = []
// this赋给self
const self = this
// 成功时的函数
function resolve(data) {
// 设置实例成功时的状态和结果值
self.PromiseState = 'fulfilled'
self.PromiseResult = data
}
// 失败时的函数
function reject(data) {
// 设置实例成功时的状态和结果值
self.PromiseState = 'rejected'
self.PromiseResult = data
}
// 执行函数
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
4.打印实例p的三种状态所对应的对象
这样一来,我们再回到html页面中的script模块,打印p的结果,图如下:
可以看到,实例对象p内部状态值和结果值都对应了构造函数promise中所设置的数据。此时我们调用reject方法并打印实例p:
let p = new Promise((resolve, reject) => {
reject('失败')
})
console.log(p);
我们调用在执行器函数内部不传入任何代码,打印实例p:
let p = new Promise((resolve, reject) => {
})
console.log(p);
思考:为什么这里打印的值为null和pending呢?
5.定义promise函数的then方法
第四步,下面我们来调用promise的then方法,传入参数搭配原生promise函数then方法固定的格式,来看执行的结果
let p = new Promise((resolve, reject) => {
resolve('成功')
})
p.then(value => {
console.log(value);
}, reason => {
})
打印结果:
注意:这里我们要实现的效果要与js内置promise函数所实现的效果一致,执行器函数内部是resolve(…)那我们就执行下面then括号中里的第一个函数。如果执行器内部是reject(…)那我相对应的就要执行then括号中而的第二个函数
出现这种情况是因为我们没有在js文件中定义then方法,所以我们可以在promise构造函数的原型上挂载一个then方法,供promise实例化对象使用。因此回到js文件中,我们要完成关于then方法的一些实现操作,我们要定义一个then函数并在这个then函数中进行如下步骤:
// 在promise函数原型上挂载一个then方法
Promise.prototype.then = function (onResolved, onRejected) {
// 成功时的then方法调用
if (this.PromiseState === 'fulfilled') {
onResolved(this.PromiseResult)
}
// 失败时的then方法调用
if (this.PromiseState === 'rejected') {
onRejected(this.PromiseResult)
}
// 状态为pending时then方法的调用
if (this.PromiseState === 'pending') {
// ...
}
}
如此一来我们就完成then方法的基本定义和内部代码编写,注意这里有几个点需要理解:
- then方法中的this指向的是实例对象
- 要对实例对象身上的状态值进行判断,再执行相应的代码
- then()方法中的两个参数onResolved,onResolved分别对应script模块中then里的的两个箭头函数
现在我们来执行script代码,效果如下:
这样我们就成功的执行了then()里的第一个箭头函数value,执行结果为”成功”,与executor执行器函数内部方法的resolve里的结果保持了一致
本文总结
这节课我们完成了关于promise实例的声明和promise构造函数内部的代码的最基本实现,以及then方法内部的最基本逻辑结构的连接。后续的文章当中我们要完善很多代码并添加其他几种promise的方法,今天就先讲到这里,谢谢大家!
本节代码
html中script模块代码
<script>
// 创建一个promise实例化对象
let p = new Promise((resolve, reject) => {
// 调用resolve函数,并传入参数"成功"
resolve('成功')
// reject('失败')
})
// 调用promise的then方法
p.then(value => {
// 执行p状态成功时的回调
console.log(value);
}, reason => {
// 执行p状态失败时的回调
console.log(reason);
})
</script>
js文件中代码
// 定义promise构造函数
function Promise(executor) {
// 设置默认状态和默认值
this.PromiseState = 'pending'
this.PromiseResult = null
// 设置一个空数组,异步时调用
this.callbacks = []
// this赋给self
const self = this
// 成功时的函数
function resolve(data) {
// 设置实例成功时的状态和结果值
self.PromiseState = 'fulfilled'
self.PromiseResult = data
}
// 失败时的函数
function reject(data) {
// 设置实例成功时的状态和结果值
self.PromiseState = 'rejected'
self.PromiseResult = data
}
// 执行函数并捕捉可能存在的异常
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
// 在promise函数原型上挂载一个then方法
Promise.prototype.then = function (onResolved, onRejected) {
// 成功时的then方法的调用
if (this.PromiseState === 'fulfilled') {
onResolved(this.PromiseResult)
}
// 失败时的then方法的调用
if (this.PromiseState === 'rejected') {
onRejected(this.PromiseResult)
}
// 状态为pending时then方法的调用
if (this.PromiseState === 'pending') {
// ...
}
}