携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情
前言
“手写Promise”系列作为前端常考点,深度检查了应聘者对Promise使用以及规范的理解,忏愧的是本人也是最近在完全通关这一模块。
此篇作为复习笔记,以及学习总结。
手写Promise包含以下知识点 👇:
- Promise基础知识
- Class 类
- 改变this指向 (call、apply和bind)
- 事件循环 Event Loop
其中Promise基础知识如果不了解或有遗忘的同学可以参考我这篇文章:《简单明了的Promise基本知识点》
本篇作为该系列最后一章,将讲解如何实现符合PromiseA+ 规范的完整Promise类,细节为👇
- Promise/A+规范2.3
- 实现**
resolvePromise**
Promise/A+规范2.3
如上Promise规范中,运行 [[Resolve]](promise, x) 需遵循以下步骤:
▪ 2.3.1 传入参数中x 与 promise 相等
如果 promise 和 x相同/为同一对象,那么用reject抛出一个 TypeError的错误。
▪ 2.3.2 传入参数中x 为 Promise
如果 x 的类型为 Promise ,则使 promise 接受 x 的状态
- 2.3.2.1 如果
x处于等待状态,promise需保持为等待态直至x被执行或拒绝 - 2.3.2.2 如果
x处于执行状态,用相同的值执行promise - 2.3.2.3 如果
x处于拒绝状态,用相同的据因拒绝promise
▪ 2.3.3传入参数中 x 为对象或函数
如果 x 为对象或者函数:
-
2.3.3.1 把
x.then赋值给then -
2.3.3.2 如果取
x.then的值时抛出错误e,则以e为据因拒绝promise -
2.3.3.3 如果
then是函数,将x作为函数的作用域this调用之。传递两个回调函数作为参数,第一个参数叫做resolvePromise,第二个参数叫做rejectPromise:-
2.3.3.3.1 如果
resolvePromise以值y为参数被调用,则运行[[Resolve]](promise, y) -
2.3.3.3.2 如果
rejectPromise以据因r为参数被调用,则以据因r拒绝promise -
2.3.3.3.3 如果
resolvePromise和rejectPromise均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用 -
2.3.3.3.4 如果调用
then方法抛出了异常e:- 2.3.3.3.4.1 如果
resolvePromise或rejectPromise已经被调用,则忽略之 - 2.3.3.3.4.2 否则以
e为据因拒绝promise
- 2.3.3.3.4.1 如果
-
2.3.3.4 如果
then不是函数,以x为参数执行promise
-
▪ 2.3.4 如果 x 不为对象或者函数,以 x 为参数执行 promise
实现**resolvePromise**
一次性消化这么长的规范想必还是有点困难,不过我们按照规则一条条实现就会简单许多了😏
首先创建
[[Resolve]](promise, x)这个函数。
我们将[[Resolve]](promise, x)命名为resolvePromise(promise2,x)
function resolvePromise(promise2, x){}
接着依次实现规范2.3细则,首先👇
2.3.1 如果
promise和x相同/为同一对象,那么用reject抛出一个TypeError的错误。
在这里面我们发现会运用到传入的promise中的reject方法以及后文还会用到resolve方法,所以我们修改下resolvePromise👇
function resolvePromise(promise2,x,resolve,reject){
}
参数解释:
promise2:then方法新返回的promise对象x:then中调用onFulfilled或onReject函数的返回值resolve:promise2的成功执行函数reject:promise2的拒绝执行函数
接着我们在原有的then方法中使用它👇
then(onFulfilled,onRejected){
....
const promise2 = new myPromise((resolve,reject)=>{
if (this.PromiseState == myPromise.FULFILLED){
setTimeout(()=>{
try {
const value = onFulfilled(this.PromiseResult)
if (value != undefined){
resolvePromise(promise2,value,resolve,reject)
}
}catch (e){
reject(e)
}
})
}else if(this.PromiseState == myPromise.REJECTED){
setTimeout(()=>{
try {
const value = onRejected(this.PromiseResult)
if (value != undefined){
resolvePromise(promise2,value,resolve,reject)
}
}catch (e){
reject(e)
}
})
}
....
})
return promise2
}
准备工作做完,现在我们只用专心的实现resolvePromise了👇
function resolvePromise(promise2,x,resolve,reject){
if (promise2 == x){
return reject(new TypeError())
}
}
下一条~2.3.2 传入参数中
x为 Promise
function resolvePromise(promise2,x,resolve,reject){
if (promise2 == x){
return reject(new TypeError())
}
//2.3.2判断传入参数是否为Promise
if (x instanceof myPromise){
//2.3.2.1 如果 `x` 处于等待状态, `promise` 需保持为等待态直至 `x` 被执行或拒绝
if (x.PromiseState == myPromise.PENDING){
x.then(y => {
resolvePromise(promise2, y, resolve, reject)
}, reject);
}else if(x.PromiseState == myPromise.FULFILLED){
// 2.3.2.2 如果 x 处于执行态,用相同的值执行 promise
resolve(x.PromiseResult);
}else if (x.PromiseState === myPromise.REJECTED) {
// 2.3.2.3 如果 x 处于拒绝态,用相同的据因拒绝 promise
reject(x.PromiseResult);
}
}
}
2.3.3传入参数中
x为对象或函数2.3.4 如果
x不为对象或者函数,以x为参数执行promise
在判断x为对象或者函数时,需要注意**null**在使用typeof时也会被识别为一个对象。所以我们应当首先就排除null类型。
function resolvePromise(promise2,x,resolve,reject){
if (promise2 == x){
return reject(new TypeError())
}
//2.3.2判断传入参数是否为Promise
if (x instanceof myPromise){
//2.3.2.1 如果 `x` 处于等待状态, `promise` 需保持为等待态直至 `x` 被执行或拒绝
if (x.PromiseState == myPromise.PENDING){
resolvePromise(promise2,x,resolve,reject)
}else if(x.PromiseState == myPromise.FULFILLED){
// 2.3.2.2 如果 x 处于执行态,用相同的值执行 promise
resolve(x.PromiseResult);
}else if (x.PromiseState === myPromise.REJECTED) {
// 2.3.2.3 如果 x 处于拒绝态,用相同的据因拒绝 promise
reject(x.PromiseResult);
}
}else if(x != null && (typeof x === 'object' || typeof x == 'function')){
let then;
try {
then = x.then
}catch (e) {
reject(e)
}
if (typeof then == 'function'){
//2.3.3.3.3 如果 `resolvePromise` 和 `rejectPromise` 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
let called = false
try{
then.call(x,
// 2.3.3.3.1 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)
y =>{
if (called)return //如果已调用,则采取首次调用
called = true
resolvePromise(promise2, y, resolve, reject);
},
// 2.3.3.3.2 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
r =>{
if (called)return //如果已调用,则采取首次调用
called = true
reject(r);
})
}catch (e) {
//2.3.3.3.4 如果调用 `then` 方法抛出了异常 `e`:
//2.3.3.3.4.1 如果 `resolvePromise` 或 `rejectPromise` 已经被调用,则忽略之
if (called)return
//2.3.3.3.4.2 否则以 `e` 为据因拒绝 `promise`
called = true
reject(e)
}
}else{
//2.3.3.4 如果 `then` 不是函数,以 `x` 为参数执行 `promise`
resolve(x)
}
}else{
//2.3.4 如果 `x` 不为对象或者函数,以 `x` 为参数执行 `promise`
resolve(x)
}
}
到此我们就完成了2.3规范中所有的细则,接着开始2.? ........好像我们已经完成所有的规范了!
大功告成🤩
完整代码
class myPromise{
static PENDING = 'pending';
static FULFILLED = 'fulfilled';
static REJECTED = 'rejected';
constructor(func){
this.PromiseState = myPromise.PENDING
this.PromiseResult = undefined
this.onFulfilledCallbacks = []
this.onRejectedCallbacks = []
try{
func(this.resolve.bind(this),this.reject.bind(this))
}catch (e){
this.reject(e)
}
}
resolve(result){
if(this.PromiseState == myPromise.PENDING){
this.PromiseState = myPromise.FULFILLED
this.PromiseResult = result
setTimeout(()=>{
this.onFulfilledCallbacks.forEach(callback=>{callback(result)})
})
}
}
reject(reason){
if (this.PromiseState == myPromise.PENDING){
this.PromiseState = myPromise.REJECTED
this.PromiseResult = reason
setTimeout(()=>{
this.onRejectedCallbacks.forEach(callback=>{callback(reason)})
})
}
}
then(onFulfilled,onRejected){
onFulfilled = typeof onFulfilled == 'function' ? onFulfilled : value => value
onRejected = typeof onRejected == 'function' ? onRejected : reason =>{ throw reason }
const promise2 = new myPromise((resolve,reject)=>{
if (this.PromiseState == myPromise.FULFILLED){
setTimeout(()=>{
try {
const value = onFulfilled(this.PromiseResult)
if (value != undefined){
resolvePromise(promise2,value,resolve,reject)
}
}catch (e){
reject(e)
}
})
}else if(this.PromiseState == myPromise.REJECTED){
setTimeout(()=>{
try {
const value = onRejected(this.PromiseResult)
if (value != undefined){
resolvePromise(promise2,value,resolve,reject)
}
}catch (e){
reject(e)
}
})
}else if(this.PromiseState === myPromise.PENDING){
this.onFulfilledCallbacks.push(onFulfilled)
this.onRejectedCallbacks.push(onRejected)
}
})
return promise2
}
}
function resolvePromise(promise2,x,resolve,reject){
if (promise2 == x){
return reject(new TypeError())
}
//2.3.2判断传入参数是否为Promise
if (x instanceof myPromise){
//2.3.2.1 如果 `x` 处于等待状态, `promise` 需保持为等待态直至 `x` 被执行或拒绝
if (x.PromiseState == myPromise.PENDING){
resolvePromise(promise2,x,resolve,reject)
}else if(x.PromiseState == myPromise.FULFILLED){
// 2.3.2.2 如果 x 处于执行态,用相同的值执行 promise
resolve(x.PromiseResult);
}else if (x.PromiseState === myPromise.REJECTED) {
// 2.3.2.3 如果 x 处于拒绝态,用相同的据因拒绝 promise
reject(x.PromiseResult);
}
}else if(x != null && (typeof x === 'object' || typeof x == 'function')){
let then;
try {
then = x.then
}catch (e) {
reject(e)
}
if (typeof then == 'function'){
//2.3.3.3.3 如果 `resolvePromise` 和 `rejectPromise` 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
let called = false
try{
then.call(x,
// 2.3.3.3.1 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)
y =>{
if (called)return //如果已调用,则采取首次调用
called = true
resolvePromise(promise2, y, resolve, reject);
},
// 2.3.3.3.2 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
r =>{
if (called)return //如果已调用,则采取首次调用
called = true
reject(r);
})
}catch (e) {
//2.3.3.3.4 如果调用 `then` 方法抛出了异常 `e`:
//2.3.3.3.4.1 如果 `resolvePromise` 或 `rejectPromise` 已经被调用,则忽略之
if (called)return
//2.3.3.3.4.2 否则以 `e` 为据因拒绝 `promise`
called = true
reject(e)
}
}else{
//2.3.3.4 如果 `then` 不是函数,以 `x` 为参数执行 `promise`
resolve(x)
}
}
}
End
本人也是反复琢磨了俩周Promise规范实现,才总结出一系列的文章。看到这里的朋友可能仍还是不太清楚,不着急自己从0按照我的思路多实现就能够完美掌握了。
\