携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情
前言
“手写Promise”系列作为前端常考点,深度检查了应聘者对Promise使用以及规范的理解,忏愧的是本人也是最近在完全通关这一模块。
此篇作为复习笔记,以及学习总结。
手写Promise包含以下知识点 👇:
- Promise基础知识
- Class 类
- 改变this指向 (call、apply和bind)
- 事件循环 Event Loop
其中Promise基础知识如果不了解或有遗忘的同学可以参考我这篇文章:《简单明了的Promise基本知识点》
看完本篇你能学到:
- 了解
Promise构造时的处理 - 了解
Promise运行机制 - 了解实现一个简易的
Promise类
定义初始结构
原生的promise我们都通过new关键字来新建实例:
const usePromise = new Promise()
首先创建一个我们手写的Promise类,命名为myPromise
class myPromise{}
其次编写其的构造函数,我们知道Promise在实例化时要求传入一个类型为函数的参数,并且会在创建时就运行这个函数。
class myPromise{
constructor(func){
func()
}
}
实现resolve和reject
随后,实例化时传入的这个func应当传入俩个参数:resolve和reject
class myPromise{
constructor(func){
func(resolve,reject)
}
}
随即迎来下一个问题:resolve和reject我们尚未声明。于是我们应该当在类中显示声明
创建这俩个方法后,编译器提示我们需要使用this关键字。原来,我们在类里面调用自身的属性时需要使用this关键字啊!
加上后编译器就提示正确了,但是我们在resolve和reject方法中需要干什么呢?
管理状态
仔细查看以下Promise流程图
我们发现resolve和reject都改变了promise的状态!但是我们好像并未赋予实例属性
PromiseState,马上给他赋予下。并且声明三个静态属性:PENDING、FULFILLED、REJECTED,将PENDING作为默认值在初始化时赋予给状态。
class myPromise{
static PENDING = 'pending';
static FULFILLED = 'fulfilled';
static REJECTED = 'rejected';
constructor(func){
this.PromiseState = myPromise.PENDING
func(this.resolve,this.reject)
}
resolve(){
}
reject(){
}
}
我们已知在原生的Promise中状态一经修改变无法修改,所以在resolve和reject中修改状态前要判断当前状态是否为初始状态pending。
class myPromise{
static PENDING = 'pending';
static FULFILLED = 'fulfilled';
static REJECTED = 'rejected';
constructor(func){
this.PromiseState = myPromise.PENDING
func(this.resolve,this.reject)
}
resolve(){
if(this.PromiseState == myPromise.PENDING){
this.PromiseState = myPromise.FULFILLED
}
}
reject(){
if (this.PromiseState == myPromise.PENDING){
this.PromiseState = myPromise.REJECTED
}
}
}
管理结果
如上图我们发现在原生的Promise中除了PromiseState外还有PromiseResult属性。而这个属性就是用来保存我们执行resolve和reject时,传递的参数。
let promise = new Promise((resolve, reject) => {
resolve('执行成功')
})
console.log(promise)
/*Promise {<fulfilled>: '执行成功'}
[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: "执行成功" */
因此,我们在我们的手写类中添加一个PromiseResult属性,并将初始值赋值为undefined,在执行resolve和reject时改变它。
class myPromise{
static PENDING = 'pending';
static FULFILLED = 'fulfilled';
static REJECTED = 'rejected';
constructor(func){
this.PromiseState = myPromise.PENDING
this.PromiseResult = undefined
func(this.resolve,this.reject)
}
resolve(result){
if(this.PromiseState == myPromise.PENDING){
this.PromiseState = myPromise.FULFILLED
this.PromiseResult = result
}
}
reject(reason){
if (this.PromiseState == myPromise.PENDING){
this.PromiseState = myPromise.REJECTED
this.PromiseResult = reason
}
}
}
this 指向问题
以上代码我们好像已经实现了一个拥有状态并能改变状态的promise类了,现在我们新建一个实例来执行下代码。
let promiseTest = new myPromise((resolve,reject)=>{
resolve('changeStateToFulfullied')
})
运行上面代码,报错 🦁:
Uncaught TypeError: Cannot read property 'PromiseState ' of undefined
原因是我们在运行resolve以及reject时,函数的this指针已经从实例类变成了运行时函数环境也就是:
{
resolve('changeStateToFulfullied')
}
因此我们需要在初始化时,固定下这俩个函数的this指针。即:
constructor(func){
this.PromiseState = myPromise.PENDING
this.PromiseResult = undefined
func(this.resolve.bind(this),this.reject.bind(this))
}
在resolve中加上console.log(result),并再次运行😎
执行成功
这样我们就实现了一个与原生Promise具有相同属性PromiseState、PromiseResult并能够改变属性的类
Next
由于将整个Promise细节堆在一起讲解篇幅会过长,我将文章也拆分为了五个小段进行描述。目的是为了让大家能够理解到不同的阶段,能够充分的消化并在实战中使用。
下一期从0实现一个基本的Promise类(二)会讲述
- 实现then方法
- 实现异步