028-86922220

建站动态

根据您的个性需求进行定制 先人一步 抢占小程序红利时代

[手写系列] 带你实现一个简单的Promise

从网站建设到定制行业解决方案,为提供网站制作、网站建设服务体系,各种行业企业客户提供网站建设解决方案,助力业务快速发展。创新互联建站将不断加快创新步伐,提供优质的建站服务。

简介

学习之前 需要先对Promise有个基本了解哦,这里都默认大家都是比较熟悉Promise的

本次将带小伙伴们实现Promise的基本功能

  1. Promise的基本骨架
  2. Promisethen
  3. Promise.then的多次调用
  4. then链式调用
  5. catch的实现
  6. finally的实现

01-搭建基本骨架

const PROMISE_STATUS_PENDING = "PROMISE_STATUS_PENDING";
const PROMISE_STATUS_FULFILLED = "PROMISE_STATUS_FULFILLED";
const PROMISE_STATUS_REJECTED = "PROMISE_STATUS_REJECTED";

class ZXPromise {
    constructor(executor) {
        this.status = PROMISE_STATUS_PENDING;
        const resolve = (value) => {
            if (this.status === PROMISE_STATUS_PENDING) {
                this.status = PROMISE_STATUS_FULFILLED;
                console.log(value);
            }
        }
        const rejected = (reason) => {
            if (this.status === PROMISE_STATUS_PENDING) {
                this.status = PROMISE_STATUS_REJECTED;
                console.log(reason);
            }
        }
        executor(resolve, rejected)
    }
}

// 初步搭建好Promise的construtor结构
const promise = new ZXPromise((resolve, rejected) => {
    resolve("123");
    rejected("wushichu")
})

02-实现Promise的then功能

const PROMISE_STATUS_PENDING = "PROMISE_STATUS_PENDING";
const PROMISE_STATUS_FULFILLED = "PROMISE_STATUS_FULFILLED";
const PROMISE_STATUS_REJECTED = "PROMISE_STATUS_REJECTED";

class ZXPromise {
	constructor(executor) {
		this.status = PROMISE_STATUS_PENDING;
		const resolve = (value) => {
			if (this.status === PROMISE_STATUS_PENDING) {
				queueMicrotask(() => {
          //因为只有pending状态才能进行变化
          if(this.status!==PROMISE_STATUS_PENDING) return
          this.status = PROMISE_STATUS_FULFILLED;
					if (this.onfufilled)
						this.onfufilled(value);
				})
			}
		}
		const rejected = (reason) => {
			if (this.status === PROMISE_STATUS_PENDING) {
				queueMicrotask(() => {
          if(this.status!==PROMISE_STATUS_PENDING) return
          this.status = PROMISE_STATUS_REJECTED;
					if (this.onrejected)
						this.onrejected(reason);
				})
			}
		}
		executor(resolve, rejected)
	}
	then(onfufilled, onrejected) {
		this.onfufilled = onfufilled;
		this.onrejected = onrejected;
	}
}

// 接下来开始写then方法
const promise = new ZXPromise((resolve, rejected) => {
	resolve("123");
	rejected("wushichu");
})

promise.then((res) => {
	console.log("res", res);
}, (err) => {
	console.log("err", err);
})

03-Promise.then多次调用

大家可以用上一部分的代码实验一下,如果多次调用,会发现只有最后一个输出,并且在定时器中使用,会出现结果为undefined

p1.then((res) => {
	console.log("res1", res);
});

p1.then((res) => {
	console.log('res2: ', res);
});

setTimeout(() => {
	p1.then((res) => {
		console.log("res4", res);
	})
}, 1000);

现在我们来解决下上述问题,看代码

const PROMISE_STATUS_PENDING = "PROMISE_STATUS_PENDING";
const PROMISE_STATUS_FULFILLED = "PROMISE_STATUS_FULFILLED";
const PROMISE_STATUS_REJECTED = "PROMISE_STATUS_REJECTED";

class ZXPromise {
	constructor(executor) {
		this.status = PROMISE_STATUS_PENDING;
		this.value = undefined;
		this.reason = undefined;
		this.onfufilled = [];
		this.onrejected = [];
		const resolve = (value) => {
			if (this.status === PROMISE_STATUS_PENDING) {
				queueMicrotask(() => {
					if (this.status !== PROMISE_STATUS_PENDING) return
					this.status = PROMISE_STATUS_FULFILLED;
					this.value = value;
					this.onfufilled.forEach(fn => {
						fn(value);
					});
				})
			}
		}
		const rejected = (reason) => {
			if (this.status === PROMISE_STATUS_PENDING) {
				queueMicrotask(() => {
					if (this.status !== PROMISE_STATUS_PENDING) return
					this.status = PROMISE_STATUS_REJECTED;
					this.reason = reason;
					this.onrejected.forEach(fn => {
						fn(reason);
					})
				})
			}
		}
		executor(resolve, rejected)
	}
	// 接下来为了Promise能够多次调用 进行优化
	then(onfufilled, onrejected) {
		if (this.status === PROMISE_STATUS_FULFILLED) {
			onfufilled(this.value);
		}
		if (this.status === PROMISE_STATUS_REJECTED) {
			onrejected(this.value);
		}
		if (this.status === PROMISE_STATUS_PENDING) {
			this.onfufilled.push(onfufilled);
			this.onrejected.push(onrejected);
		}

	}
}

04-then方法的链式调用

要想实现链式调用,那么then方法肯定是将Promise对象又给返回出来了,说到这了大家有没有思路呢?

const PROMISE_STATUS_PENDING = "PROMISE_STATUS_PENDING";
const PROMISE_STATUS_FULFILLED = "PROMISE_STATUS_FULFILLED";
const PROMISE_STATUS_REJECTED = "PROMISE_STATUS_REJECTED";

class ZXPromise {
	constructor(executor) {
		this.status = PROMISE_STATUS_PENDING;
		this.value = undefined;
		this.reason = undefined;
		this.onfufilled = [];
		this.onrejected = [];
		const resolve = (value) => {
			if (this.status === PROMISE_STATUS_PENDING) {
				queueMicrotask(() => {
					if (this.status !== PROMISE_STATUS_PENDING) return
					this.status = PROMISE_STATUS_FULFILLED;
					this.value = value;
					this.onfufilled.forEach(fn => {
						fn(value);
					});
				})
			}
		}
		const rejected = (reason) => {
			if (this.status === PROMISE_STATUS_PENDING) {
				queueMicrotask(() => {
					if (this.status !== PROMISE_STATUS_PENDING) return
					this.status = PROMISE_STATUS_REJECTED;
					this.reason = reason;
					this.onrejected.forEach(fn => {
						fn(reason);
					})
				})
			}
		}
		try{
			executor(resolve, rejected)
		}catch(err){
			console.log(err);
		}
		
	}
	
	then(onfufilled, onrejected) {
		return new ZXPromise((resolve, rejected) => {
			if (this.status === PROMISE_STATUS_FULFILLED) {
				try {
					//如果then中有返回值,就会作为下一个then所接收的值
					const value = onfufilled(this.value);
					resolve(value);
				} catch (err) {
					rejected(err);
				}
				
			}
			if (this.status === PROMISE_STATUS_REJECTED) {
				try {
					const value = onrejected(this.value);
					resolve(value);
				} catch (err) {
					rejected(err);
				}
			}
			if (this.status === PROMISE_STATUS_PENDING) {
				try {
					this.onfufilled.push(() => {
						const value = onfufilled(this.value);
						resolve(value);
					});
				} catch (err) {
					rejected(err);
				}
				try {
					this.onrejected.push(() => {
						const value = onrejected(this.value);
						resolve(value);
					});
				} catch (err) {
					rejected(err);
				}
			}
		})
	}
}


const promise = new ZXPromise((resolve, rejected) => {
	resolve("123");
	rejected("wushichu");
})
promise.then((res) => {
	console.log("res1:", res);
	return "abc";
}, (err) => {
	console.log("err1", err);
}).then((res) => {
	console.log("res2", res);
}, (err) => {
	console.log("err2", err);
})

05-catch方法实现

catch方法实际上是then第二个参数的语法糖,说到这里大家有没有明白什么呢?

const PROMISE_STATUS_PENDING = "PROMISE_STATUS_PENDING";
const PROMISE_STATUS_FULFILLED = "PROMISE_STATUS_FULFILLED";
const PROMISE_STATUS_REJECTED = "PROMISE_STATUS_REJECTED";

const execFnWithCatchError = (execFn, value, resolve, reject) => {
    try {
        const result = execFn(value);
        resolve(result);
    } catch (err) {
        reject(err);
    }
}

class ZXPromise {
    constructor(executor) {
        this.status = PROMISE_STATUS_PENDING;
        this.value = undefined;
        this.reason = undefined;
        this.onfufilled = [];
        this.onrejected = [];
        const resolve = (value) => {
            if (this.status === PROMISE_STATUS_PENDING) {
                queueMicrotask(() => {
                    if (this.status !== PROMISE_STATUS_PENDING) return
                    this.status = PROMISE_STATUS_FULFILLED;
                    this.value = value;
                    this.onfufilled.forEach(fn => {
                        fn(value);
                    });
                })
            }
        }
        const rejected = (reason) => {
            if (this.status === PROMISE_STATUS_PENDING) {
                queueMicrotask(() => {
                    if (this.status !== PROMISE_STATUS_PENDING) return
                    this.status = PROMISE_STATUS_REJECTED;
                    this.reason = reason;
                    this.onrejected.forEach(fn => {
                        fn(reason);
                    })
                    return this.reason;
                })
            }
        }
        executor(resolve, rejected)
    }

    then(onfufilled, onrejected) {
        //这一段是为了将错误代码传递下去的
        const defaultOnRejected = err => { throw err }
        onrejected = onrejected || defaultOnRejected
        return new ZXPromise((resolve, rejected) => {
            if (this.status === PROMISE_STATUS_FULFILLED && onfufilled) {
                execFnWithCatchError(onfufilled, this.value, resolve, rejected);
            }
            if (this.status === PROMISE_STATUS_REJECTED && onrejected) {
                execFnWithCatchError(onrejected, this.reason, resolve, rejected);
            }
            if (this.status === PROMISE_STATUS_PENDING) {
                if (onfufilled)
                    this.onfufilled.push(() => {
                        execFnWithCatchError(onfufilled, this.value, resolve, rejected);
                    });
                if (onrejected) {
                    this.onrejected.push(() => {
                        execFnWithCatchError(onrejected, this.reason, resolve, rejected);
                    });
                }
            }
        })
    }
    catch(onrejected) {
        return this.then(undefined, onrejected);
    }
}

06-finally的实现

finally就是要在最后执行的函数,无论什么情况,实现起来也是非常简单

    finally(fn) {
        return this.then(() => { fn() }, () => { fn() });
    }

07-完整代码总览

const PROMISE_STATUS_PENDING = "PROMISE_STATUS_PENDING";
const PROMISE_STATUS_FULFILLED = "PROMISE_STATUS_FULFILLED";
const PROMISE_STATUS_REJECTED = "PROMISE_STATUS_REJECTED";

const execFnWithCatchError = (execFn, value, resolve, reject) => {
    try {
        const result = execFn(value);
        resolve(result);
    } catch (err) {
        reject(err);
    }
}

class ZXPromise {
    constructor(executor) {
        this.status = PROMISE_STATUS_PENDING;
        this.value = undefined;
        this.reason = undefined;
        this.onfufilled = [];
        this.onrejected = [];
        const resolve = (value) => {
            if (this.status === PROMISE_STATUS_PENDING) {
                queueMicrotask(() => {
                    if (this.status !== PROMISE_STATUS_PENDING) return
                    this.status = PROMISE_STATUS_FULFILLED;
                    this.value = value;
                    this.onfufilled.forEach(fn => {
                        fn(value);
                    });
                })
            }
        }
        const rejected = (reason) => {
            if (this.status === PROMISE_STATUS_PENDING) {
                queueMicrotask(() => {
                    if (this.status !== PROMISE_STATUS_PENDING) return
                    this.status = PROMISE_STATUS_REJECTED;
                    this.reason = reason;
                    this.onrejected.forEach(fn => {
                        fn(reason);
                    })
                    return this.reason;
                })
            }
        }
        executor(resolve, rejected)
    }

    then(onfufilled, onrejected) {
        //这一段是为了将错误代码传递下去的
        const defaultOnRejected = err => { throw err }
        onrejected = onrejected || defaultOnRejected
        return new ZXPromise((resolve, rejected) => {
            if (this.status === PROMISE_STATUS_FULFILLED && onfufilled) {
                execFnWithCatchError(onfufilled, this.value, resolve, rejected);
            }
            if (this.status === PROMISE_STATUS_REJECTED && onrejected) {
                execFnWithCatchError(onrejected, this.reason, resolve, rejected);
            }
            if (this.status === PROMISE_STATUS_PENDING) {
                if (onfufilled)
                    this.onfufilled.push(() => {
                        execFnWithCatchError(onfufilled, this.value, resolve, rejected);
                    });
                if (onrejected) {
                    this.onrejected.push(() => {
                        execFnWithCatchError(onrejected, this.reason, resolve, rejected);
                    });
                }
            }
        })
    }
    catch(onrejected) {
        return this.then(undefined, onrejected);
    }

    finally(fn) {
        return this.then(() => { fn() }, () => { fn() });
    }
}

当前题目:[手写系列] 带你实现一个简单的Promise
网址分享:http://www.tsicrk.com/article/dsojhic.html

其他资讯

让你的专属顾问为你服务

2.6153s