手写Promise(个人笔记)
一步一步手写Promise
本人笔记,有不对的地方欢迎指正,谢谢各位大佬。
第一步:先声明一个类,以及一些需要用到的属性、方法;
说明:首先我们最常用promise的几个方法resolve,reject,then我们需要先定义出来,另外我们要知道Promise是异步操作,而异步操作都是有最基本的三种状态的(等待,成功,失败),所以状态我们也需要定义。另外,声明一个Promise实例时,我们会向它的构造函数中传入一个执行器,这个执行器是立即执行的,并且会将resolve,reject两个方法当作参数传递进去。还有就是then方法的声明要注意,then方法是在实例上调用的,所以需要将它声明在类的原型上。
第二步:resolve、reject和then方法中需要做哪些事情(暂时不考虑异步情况)
说明:其实resolve和reject要做的事情很简单,只需要将promise的状态改为成功或者失败,并将传入的值保存起来就ok了。但是需要注意的是,Promise的状态一旦确定为成功或者失败,就不可再更改状态,所以需要在resolve和reject方法的开始必须加上一个状态的判断,大家有时间可以去试一下,运行了resolve过后再运行reject是不会生效的。最后then方法中直接将保存下来的值传入相对应的方法中执行即可。当然,这是在不考虑异步情况下可以这样想,但是不考虑异步的话,Promise也没啥存在的意义,这里主要是方便理解整个promise的执行流程。接下来,改造一下这个方法来实现真正的Promise。
第三步:异步情况下resolve、reject和then的处理方式。
说明:其实加入异步逻辑过后的代码也非常简单,无非是在then方法中将两种状态下的回调函数也保存起来,然后在执行resolve的时候将其执行即可。但是还有一点没有考虑到,就是then方法的链式调用。我们知道Promise声明后,then方法是可以在其实例对象上进行链式调用的,这就说明会有多个处理函数需要执行,下面我们继续来改造。
第四步:实现then方法的链式调用。
实现链式调用之前我们需要了解链式调用的原理:每一个then传入的值都是上一个then方法的返回值,而这就说明每一个返回值都应该支持调用then这个方法,所以,我们每一个then最后返回的都应该是一个Promise对象。(因为代码比较长了,用代码块来展示)
// 先定义Promise类的三种状态
const PENDING = "pengding";
const SUCCESS = "success";
const ERROR = "error";
class MyPromise {
constructor (fun) {
fun(this.resolve, this.reject);
}
status = PENDING; // 初始化promise的状态为pending
value = undefined; // 成功后的值
reason = undefined; // 失败后的原因
successCallback = [];
errorCallback = [];
resolve = value => {
// 判断状态是否为等待,如果不是则直接return
if (this.status !== PENDING) return;
// 将promise的状态设置为成功
this.status = SUCCESS;
// 将成功后的值保存起来
this.value = value;
// 执行成功回调函数
while (this.successCallback.length) this.successCallback.shift()(value);
}
reject = reason => {
// 判断状态是否为等待,如果不是则直接return
if (this.status !== PENDING) return;
// 将promise的状态设置为成功
this.status = ERROR;
// 将成功后的值保存起来
this.reason = reason;
// 执行失败回调函数
while (this.errorCallback.length) this.errorCallback.shift()(reason);
}
then (successCallback, errorCallback) {
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === SUCCESS) {
setTimeout(() => {
let x = successCallback(this.value);
// 判断x是普通值还是promise对象
// 如果是普通值,直接调用resolve
// 如果是promise对象,查看promise对象返回的结果
// 再根据promise对象返回的结果,决定调用resolve还是reject
resolvePromise(promise2, x, resolve, reject);
}, 0);
} else if (this.status === ERROR) {
setTimeout(() => {
let x = errorCallback(this.resonse);
resolvePromise(promise2, x, resolve, reject);
},0)
} else {
this.successCallback.push(() => {
setTimeout(() => {
let x = successCallback(this.value);
resolvePromise(promise2, x, resolve, reject);
}, 0);
});
this.errorCallback.push(() => {
setTimeout(() => {
let x = errorCallback(this.resonse);
resolvePromise(promise2, x, resolve, reject);
}, 0);
});
}
});
return promise2;
}
catch (fallCallback) {
return this.then(undefined, fallCallback);
}
}
function resolvePromise (promise, x, resolve, reject) {
// 这里排除掉promise自己返回自己的问题
if (promise === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>').message);
}
if (x instanceof MyPromise) {
x.then(resolve, reject);
} else {
resolve(x);
}
}
说明:then的链式调用主要是将每一个then的返回值封装成一个promise,然后再调用这个promise的then方法去继续执行,所以在then方法中我们声明了一个promise2对象,在这个Promise的执行器里我们再去执行上一个promise的then方法中需要做的事情。其他的问题在注释中已经写的比较清楚了。最后我们顺带实现了一个catch方法,因为这个方法是打印Promise中的一些失败的信息,所以很简单,只需要在内部调用then方法并只传入失败回调函数即可。
第五步:扩展Promise的两个静态函数all、resolve
说明:首先大家要先搞清楚这两个静态方法的使用,这里就不过多介绍了,大家可以自行去查资料看一下。all方法中主要是先将传入的数组遍历,拿到每一项的值后先判断是否为Promise对象,如果是,则执行它的then方法,拿到它的返回值,然后通过addData方法添加到需要返回的数组里面,如果不是则直接将值添加到返回数组中。resolve方法就非常简单了,同样先判断是否为Promise对象,如果是直接返回这个对象,如果不是,则包裹到Promise中进行返回。
ok,大功告成,end!
本文地址:https://blog.csdn.net/qq_24719349/article/details/109281322
上一篇: MySQL原理探索——01 基础架构
下一篇: PHP爬虫抓取网页数据
推荐阅读
-
前端笔记之ES678&Webpack&Babel(下)AMD|CMD规范&模块&webpack&Promise对象&Generator函数
-
Linux 命令个人笔记
-
如何从零开始利用js手写一个Promise库详解
-
【学习笔记】C语言习题:有n个人围成一圈,顺序排号。从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位。
-
数据库个人笔记(2) -- 基础篇
-
数据库个人笔记(1)-- 基础篇
-
个人笔记(一)正确使用equals方法
-
轻松熊喵喵个人笔记 -- Python入门
-
tensorflow基本用法个人笔记
-
机器学习个人笔记——(二)线性回归,最小二乘法和梯度下降