ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

教你如何手写一个Promise

2022-02-25 23:58:27  阅读:264  来源: 互联网

标签:resolve res MyPromise 如何 Promise reject catch promise 手写


想要源码的可以看这里,里面也有一些其他的知识

想要手写一个promise,首先就要了解promise,想必大家都被过一些promise的面试题,知道一些promise的用法,主要考的就是一种异步编程的思想。

了解promise

我们先来看看直接输出一个promise对象会是什么,通过代码:

var p = new Promise((resolve,reject)=>{});
console.log(p);

可以看到输出结果Promise大致由它的状态PromiseState,它的值PromiseResult和它原型上面的方法组成。

promise对象有一个函数当作参数,函数里又分别有两个参数,分别是resolve和reject,当调用resolve()时就会运行prototype上的then()方法,当调用reject()时就会运行prototype上的catch()方法,这里的then,catch都是微任务,所谓微任务就是之宏任务运行完之后所运行的任务。就好比去银行办业务,你的要办的业务相当于宏任务,等你办完后银行工作人员会推荐与你业务相关的拓展业务,这个拓展业务就相当于微任务。

promise的状态有三种:等待(pending)、已完成(fulfilled)、已拒绝(rejected),并且状态只能由等待到完成或者等待到拒接。

开始写

了解promise之后我们就能把基本的架构写出来了。

function MyPromise(fn) {
        // promise 的状态
        this.PromiseState = "pendding";
        // promise 的值
        this.PromiseResult = undefined;
        var resolve = (value) => {};
        var reject = (errValue) => {};
        if (fn) {
          fn(resolve, reject);
        }
      }

这里定义初始状态pedding,和初始值undefined,resolve,reject两个方法。

完成then

首先先完成then的成功运作,如何能让如下代码成功输出:

var p = new MyPromise((resolve, reject) => {
        resolve("resolve");
      });
      p.then((res) => {
        console.log(res);
        console.log("then执行");
      });

这里就需要完善resolve和原型对象上写then方法:

// 定义一个函数对象,用来注册then中的callback
this.thenCallback = undefined;
var resolve = (value) => {
					// 更改promise的状态和值
					if (this.PromiseState == "pendding") {
						this.PromiseState = "fulfilled";
						this.PromiseResult = value;
						if (value instanceof MyPromise) {
							value.then((res) => {
								if (this.thenCallback) {
									this.thenCallback(res);
								}
							});
						} else {
							setTimeout(() => {
								if (this.thenCallback) {
									this.thenCallback(value);
								}
							});
						}
					}
				};
MyPromise.prototype.then = function (callback) {
				return new MyPromise((resolve, reject) => {
					this.thenCallback = (value) => {
						// 在使用链式调用的时候,可能第一个调用的不是catch
						// 使用我们在做检测时会借助then来将catch的信息向下传递
						// 所以我们检测到触发thenCallback的对象是rejected时
						// 我们就继续调用下一个reject
						if (this.promiseState == "rejected") {
							reject(value);
						} else {
							var res = callback(value);
							// 这里防止中间返回是一个promise对象它会继续找then,直接让他调用reject
							if (res instanceof MyPromise && res.promiseState == "rejected") {
								res.catch((errValue) => {
									reject(errValue);
								});
							} else {
								// 这里定义给变量res在调用resolve是为解决.then()的链式调用
								resolve(res);
							}
						}
					};
				});
			};

定义一个函数对象,用来注册then中的callback,首先判断promise的状态,如果是pendding则转换成fulfilled,并将参数值赋值给promiseResult;

if (value instanceof MyPromise)是为了判断value是否是一个Promise对象,如果是就使用自己定义的then,因为then时异步执行的,所以使用setTimeout

当then链式调用时,如then().then(),第一个then中如果有返回值,那么这个返回值将会作为第二个then中的参数,所以需要每个then返回一个新的promise对象return new MyPromise()。

这里再封装一个MyPromise.resolve的快捷调用:

MyPromise.resolve = (value) => {
				return new MyPromise((resolve, reject) => {
					resolve(value);
				});
			};

完成catch

catch与then大致相同,只需要稍作修改。这里完善reject方法和原型上的catch:


this.catchCallback = undefined;
var reject = (errValue) => {
					if (this.promiseState == "pendding") {
						this.promiseState = "rejected";
						this.promiseResult = errValue;
						// 判断写没写catch()
						setTimeout(() => {
							if (this.catchCallback) {
								this.catchCallback(errValue);
							} else if (this.thenCallback) {
								this.thenCallback(errValue);
							} else {
								throw "catch is not defined!!!!";
							}
						});
					}
				};

首先判断promise的状态,如果是pendding则转换成frejected,并将参数值赋值给promiseResult;

这里有可能再调用catch前还调用了then方法,所以使用else if判断是不是,时就运行this.thenCallback(errValue);,因为之前在then会判断promise状态是不是rejected,如果是就重新调用reject()方法。

MyPromise.prototype.catch = function (callback) {
				return new MyPromise((resolve, reject) => {
					this.catchCallback = (errValue) => {
						var res = callback(errValue);
						reject(errValue);
					};
				});
			};

这里也继续封装一个MyPromise.reject的快捷调用:

MyPromise.reject = (errValue) => {
				return new MyPromise((resolve, reject) => {
					reject(errValue);
				});
			};

promise中的api,all和race

all和race传入的参数都是一个数组,all将会等最长时间结束后按数组的顺序,而race则会执行最早的那一个。

MyPromise.all = (promiseArr) => {
				let resArr = [];
				return new MyPromise((resolve, reject) => {
					promiseArr.forEach((item, index) => {
						item
							.then((res) => {
								resArr[index] = res;
								var allResolve = promiseArr.every((_item) => {
									return _item.promiseState == "fulfilled";
								});
								// 判断传过来的数组中所有promise对象状态都已完成
								if (allResolve) {
									resolve(resArr);
								}
							})
							.catch((err) => {
								reject(err);
							});
					});
				});
			};
MyPromise.race = (promiseArr) => {
				let resArr = [];
				return new MyPromise((resolve, reject) => {
					promiseArr.forEach((item, index) => {
						item
							.then((res) => {
								resolve(res);
							})
							.catch((err) => {
								reject(err);
							});
					});
				});
			};

手写promise的化没有长时间的叙述的话不好将清楚,建议找到将promise源码的视频一步一步分析

标签:resolve,res,MyPromise,如何,Promise,reject,catch,promise,手写
来源: https://blog.csdn.net/ose_huang/article/details/123141668

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有