为了能够更好的理解和使用promise,我觉得还是得看一看源码,了解其内部的核心机制 由于Promise内容过多,下面我们由浅入深,一点一点的实现。 本篇篇幅很长,因为我也是一点点写的,要是直接全部写完的代码扔上来,我也看得晕,哈哈加油吧,慢慢看
1.声明Promise并绑定this
let p = new PromiseA((resolve, reject) => {
resolve("成功");
// reject("失败");
});
console.log(p);
(1)声明
首先,我们声明一个 PromiseA 来代表我们自己写的promise
我们知道,promise的特性: (1)有三个状态pending,fulfilled,rejected (2)状态一旦改变,后续状态不可改变 定义时,传入一个参数为 resolve 和 rejected 的函数 executor
class PromiseA {
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
// 按照定义,我们写出promise
constructor(executor) {
this.status = PromiseA.PENDING;
this.value = null;
// 先不绑定,看看效果
executor(this.resolve, this.reject);
}
// 由于resolve和reject执行时是在promise外部,隐式传递导致this丢失,所以需要另外绑定
resolve(value) {
this.status = PromiseA.FULFILLED;
this.value = value;
}
reject(reason) {
this.status = PromiseA.REJECTED;
this.value = reason;
}
}
resolve和reject不绑定this,就会出现这样的报错,找不到this的status
(2)绑定this 和 保护状态
class PromiseA {
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(executor) {
this.status = PromiseA.PENDING;
this.value = null;
// 绑定this
executor(this.resolve.bind(this), this.reject.bind(this));
}
resolve(value) {
// 判断一下,如果状态不是pending那么状态以及改变,不能再次改变
if (this.status === PromiseA.PENDING) {
this.status = PromiseA.FULFILLED;
this.value = value;
}
}
reject(reason) {
if (this.status === PromiseA.PENDING) {
this.status = PromiseA.REJECTED;
this.value = reason;
}
}
}
(3)定义时的错误处理
我们知道,如果我们在定义promise时,在状态改变之前出现了错误,这个promise会之间变成reject状态
let p = new Promise((resolve,reject)=>{
console.log(abc); // abc未定义,状态变成rejected
resolve("原生成功")
})
console.log(p);
let p = new PromiseA((resolve, reject) => {
console.log(abc);
resolve("成功");
});
console.log(p);
别说状态改变了,后面的代码都执行不了,所以,我们不能因为promise的错误就中断所有代码的执行
class PromiseA {
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(executor) {
this.status = PromiseA.PENDING;
this.value = null;
// try catch 捕捉异常
try {
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
this.reject(error)
}
}
resolve(value) {
if (this.status === PromiseA.PENDING) {
this.status = PromiseA.FULFILLED;
this.value = value;
}
}
reject(reason) {
if (this.status === PromiseA.PENDING) {
this.status = PromiseA.REJECTED;
this.value = reason;
}
}
}
2.then方法的基本构建
我们知道then方法有两个参数 onFulfilled 和 onRejected 两个函数 (1)当我们resolve时,then触发onFulfilled (2)当我们reject时,then触发onRejected (3)当 resolve 或 reject 被异步操作延迟时,也就是状态为pending时,then的内部处理 (4)重点:then方法会将onFulfilled 或 onRejected 内产生的错误传递给下一个then或者catch,由于这还没有到链式传递那块,先用try catch代替 (5)then内部执行的函数是异步回调,是异步操作!! (6)还有一个就是我们最容易忽略的点,当 resolve 或 reject 被异步操作延迟时,resolve 或 reject后面的代码应该是同步的,先执行,而不应该是我们then执行完后再执行
(1)构建then
class PromiseA {
// ...上面的代码
then(onFulfilled, onRejected) {
// 防止then中传入的参数为空时报错
if (typeof onFulfilled !== "function") {
onFulfilled = () => { };
}
if (typeof onRejected !== "function") {
onRejected = () => { };
}
if (this.status === PromiseA.FULFILLED) {
// 直接执行的话就是同步了,使用setTimeOut,变成异步
setTimeout(() => {
// 我们知道promise内部会将错误传递给下一个then,或者catch处理
// 我们这里就先用trycatch处理来模仿一下
try {
onFulfilled(this.value);
} catch (error) {
onRejected(error);
}
});
}
if (this.status === PromiseA.REJECTED) {
setTimeout(() => {
try {
onRejected(this.value);
} catch (error) {
onRejected(error);
}
});
}
}
}
let p = new PromiseA((resolve, reject) => {
resolve("成功");
});
p.then(value => {
// 当发送错误时,直接catch到error那处理
// console.log(abc);
console.log("value:", value);
}, error => {
console.log("error:", error);
})
console.log(p);
(2)当状态为pending时,then的处理
当状态为 pending 时,这时候我们的resolve或reject八成是被套在了定时器里变异步了
如果我们不对pending状态进行处理,那么我们写的promise.then就无法处理
let p = new PromiseA((resolve, reject) => {
setTimeout(() => {
resolve("成功");
});
});
p.then(value => {
console.log("value:", value);
}, error => {
console.log("error:", error);
});
console.log(p);
(1)使用callback数组处理 和 错误处理
那我们该如何处理pending状态时的then呢?又要如何拿到异步处理完成后,变化的状态呢? (1)其实,我们可以在构造函数内,新增一个 callbacks 数组(队列) 来存储我们未执行的onFulfilled和onRejected (2)然后,当异步任务完成时,触发resolve或reject,我们再通过resolve和reject内部来触发callback,这样我们就能够实现一个 延时状态改变了 (3)当然,在pending状态内部,我们也还是要进行错误的处理
class PromiseA {
//...静态属性
constructor(executor) {
// ... status, value
this.callbacks = [];
// ...executor
}
resolve(value) {
if (this.status === PromiseA.PENDING) {
this.status = PromiseA.FULFILLED;
this.value = value;
// 当异步任务结束,触发resolve状态改变时,调用callback
this.callbacks.map(callback => {
// 上面说的错误问题依然存在,所以要用try-catch捕获
try {
callback.onFulfilled(this.value);
} catch (error) {
callback.onRejected(error);
}
});
}
}
reject(reason) {
if (this.status === PromiseA.PENDING) {
this.status = PromiseA.REJECTED;
this.value = reason;
this.callbacks.map(callback => {
try {
callback.onRejected(this.value);
} catch (error) {
callback.onRejected(error);
}
});
}
}
then(onFulfilled, onRejected) {
if (typeof onFulfilled !== "function") {
onFulfilled = () => { };
}
if (typeof onRejected !== "function") {
onRejected = () => { };
}
if (this.status === PromiseA.PENDING) {
// 当状态为pending,我们把没有执行的onFulfilled和onRejected存储起来
// 等待状态的改变再来调用
this.callbacks.push({
onFulfilled,
onRejected
});
}
if (this.status === PromiseA.FULFILLED) {
setTimeout(() => {
try {
onFulfilled(this.value);
} catch (error) {
onRejected(error);
}
});
}
if (this.status === PromiseA.REJECTED) {
setTimeout(() => {
try {
onRejected(this.value);
} catch (error) {
onRejected(error);
}
});
}
}
}
(2)resolve和reject后方代码的同步执行问题
如何解决这个问题: 其实我们只需要把callback执行时,把callback变成异步执行就行,这样resolve后面的代码就能先执行了
上面代码写完了之后,看似没有什么问题,但实际上,我们在resolve后面添加一个行代码就能发现问题了
let p = new PromiseA((resolve, reject) => {
setTimeout(() => {
resolve("成功");
console.log("666");
});
});
p.then(value => {
console.log("value:", value);
}, error => {
console.log("error:", error);
});
console.log(p);
666竟然在then执行完之后才输出,这就很不应该了,它应该是在then执行之前输出的
class PromiseA {
// ...
constructor(executor) {...}
resolve(value) {
if (this.status === PromiseA.PENDING) {
this.status = PromiseA.FULFILLED;
this.value = value;
// callback变成异步执行,这样resolve后方的代码就能先执行了
setTimeout(() => {
this.callbacks.map(callback => {
try {
callback.onFulfilled(this.value);
} catch (error) {
callback.onRejected(error);
}
});
});
}
}
reject(reason) {
if (this.status === PromiseA.PENDING) {
this.status = PromiseA.REJECTED;
this.value = reason;
setTimeout(() => {
this.callbacks.map(callback => {
try {
callback.onRejected(this.value);
} catch (error) {
callback.onRejected(error);
}
});
});
}
}
then(onFulfilled, onRejected) {...}
}
3.then的链式传递的实现
链式操作其实也就是我们把 onFulfilled 和 onRejected 执行后的结果封装成一个新的promise传给下一个then而已。 (1)把 onFulfilled 和 onRejected 执行后的返回值封装成一个新的promise(resolve,reject) (2)返回值为普通值,直接resolve 或 reject (3)返回值为promise,获得其内部resolve或reject的值,并通过resolve 或 reject传递 (4)注意其内部可能产生的错误,并通过trycatch进行错误处理,完成错误的链式传递 注意: 返回值为promise时,内部的resolve或reject被延迟执行,和上面的情况类似,但实际上,我们上面的步骤就已经帮我们全部处理完了,由于我们是通过调用返回值promise的 then来实现参数传递的,因为返回值为promise,所以我们上面封装的它也有效。(嘿嘿,所以我们不用考虑这个了)
(1)返回值的封装
封装时,要考虑上面说的,返回值为普通值时,和返回值为promise时的情况
class PromiseA {
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(executor) {
this.status = PromiseA.PENDING;
this.value = null;
this.callbacks = [];
try {
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
this.reject(error);
}
}
resolve(value) {
if (this.status === PromiseA.PENDING) {
this.status = PromiseA.FULFILLED;
this.value = value;
setTimeout(() => {
this.callbacks.map(callback => {
try {
callback.onFulfilled(this.value);
} catch (error) {
callback.onRejected(error);
}
});
});
}
}
reject(reason) {
if (this.status === PromiseA.PENDING) {
this.status = PromiseA.REJECTED;
this.value = reason;
setTimeout(() => {
this.callbacks.map(callback => {
try {
callback.onRejected(this.value);
} catch (error) {
callback.onRejected(error);
}
});
});
}
}
then(onFulfilled, onRejected) {
if (typeof onFulfilled !== "function") {
onFulfilled = () => { };
}
if (typeof onRejected !== "function") {
onRejected = () => { };
}
if (this.status === PromiseA.PENDING) {
this.callbacks.push({
onFulfilled,
onRejected
});
}
if (this.status === PromiseA.FULFILLED) {
return new PromiseA((resolve, reject) => {
setTimeout(() => {
try {
let res = onFulfilled(this.value);
if (res instanceof PromiseA) {
// 如果返回值是 一个promise,则直接调用其then函数
// 并且把 我们的resolve传入,当作onFulfilled函数来接收其内部resolve的值
res.then(resolve, reject);
} else {
// 返回值为普通值,则直接resolve
resolve(res);
}
} catch (error) {
// onRejected(error);
// 错误处理也交给这个新的promise处理,这样就完成了错误的链式传递
reject(error);
}
});
});
}
if (this.status === PromiseA.REJECTED) {
return new PromiseA((resolve, reject) => {
setTimeout(() => {
try {
let res = onRejected(this.value);
if (res instanceof PromiseA) {
res.then(resolve, reject);
} else {
reject(res);
}
} catch (error) {
reject(error);
}
});
});
}
}
}
// test1
let p = new PromiseA((resolve, reject) => {
resolve("成功");
});
p.then(value => {
console.log("value:", value);
return new PromiseA(resolve => {
resolve("666");
setTimeout(() => {
resolve("666");
});
});
}, error => {
console.log("error:", error);
}).then(value => {
console.log(value);
})
// test2
let p = new PromiseA((resolve, reject) => {
resolve("成功");
});
p.then(value => {
console.log("value:", value);
return new PromiseA(resolve => {
// resolve被延迟时
setTimeout(() => {
resolve("666");
});
});
}, error => {
console.log("error:", error);
}).then(value => {
console.log(value);
})
两次test结果一样,封装成功
let p = new PromiseA((resolve, reject) => {
resolve("成功");
});
p.then(value => {
// 测试错误的链式传递
console.log(abc);
console.log("value:", value);
}, error => {
console.log("error第一次:", error);
}).then(value => {
console.log(value);
}, error => {
console.log("error第二次:", error);
})
4.静态方法resolve和reject的构建
到这,我们已经实现了promise的大量功能了 这两个静态方法实际上就是调用我们上面写的就行了,会写then了,这两个就很简单了
实际上,Promise.resolve就直接创建一个新的promise,然后resolve就行 (1)Promise.resolve传入值为普通值 (2)Promise.resolve传入值为promise对象
class PromiseA {
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(executor) {
this.status = PromiseA.PENDING;
this.value = null;
this.callbacks = [];
try {
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
this.reject(error);
}
}
resolve(value) {
if (this.status === PromiseA.PENDING) {
this.status = PromiseA.FULFILLED;
this.value = value;
setTimeout(() => {
this.callbacks.map(callback => {
try {
callback.onFulfilled(this.value);
} catch (error) {
callback.onRejected(error);
}
});
});
}
}
reject(reason) {
if (this.status === PromiseA.PENDING) {
this.status = PromiseA.REJECTED;
this.value = reason;
setTimeout(() => {
this.callbacks.map(callback => {
try {
callback.onRejected(this.value);
} catch (error) {
callback.onRejected(error);
}
});
});
}
}
then(onFulfilled, onRejected) {
// 防止then中传入的参数为空时报错
if (typeof onFulfilled !== "function") {
onFulfilled = () => { };
}
if (typeof onRejected !== "function") {
onRejected = () => { };
}
if (this.status === PromiseA.PENDING) {
this.callbacks.push({
onFulfilled,
onRejected
});
}
if (this.status === PromiseA.FULFILLED) {
return new PromiseA((resolve, reject) => {
setTimeout(() => {
try {
let res = onFulfilled(this.value);
if (res instanceof PromiseA) {
res.then(resolve, reject);
} else {
resolve(res);
}
} catch (error) {
reject(error);
}
});
});
}
if (this.status === PromiseA.REJECTED) {
return new PromiseA((resolve, reject) => {
setTimeout(() => {
try {
let res = onRejected(this.value);
if (res instanceof PromiseA) {
res.then(resolve, reject);
} else {
reject(res);
}
} catch (error) {
reject(error);
}
});
});
}
}
static resolve(value) {
return new PromiseA((resolve, reject) => {
if (value instanceof PromiseA) {
value.then(resolve, reject);
} else {
resolve(value);
}
});
}
static reject(reason) {
return new PromiseA((resolve, reject) => {
if (reason instanceof PromiseA) {
reason.then(resolve, reject);
} else {
reject(reason);
}
});
}
}
// 传入的值为普通值
PromiseA.resolve(666).then(value => {
console.log("resolve:", value);
}, error => {
console.log("reject:", error);
})
PromiseA.reject(666).then(value => {
console.log("resolve:", value);
}, error => {
console.log("reject:", error);
})
// 传入的值为promise对象
let p = new PromiseA((resolve, reject) => {
resolve("成功");
// reject("失败");
});
PromiseA.resolve(p).then(value => {
console.log("resolve:", value);
}, error => {
console.log("reject:", error);
});
PromiseA.reject(p).then(value => {
console.log("resolve:", value);
}, error => {
console.log("reject:", error);
})
5.完整核心代码:
class PromiseA {
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(executor) {
this.status = PromiseA.PENDING;
this.value = null;
this.callbacks = [];
try {
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
this.reject(error);
}
}
resolve(value) {
if (this.status === PromiseA.PENDING) {
this.status = PromiseA.FULFILLED;
this.value = value;
setTimeout(() => {
this.callbacks.map(callback => {
try {
callback.onFulfilled(this.value);
} catch (error) {
callback.onRejected(error);
}
});
});
}
}
reject(reason) {
if (this.status === PromiseA.PENDING) {
this.status = PromiseA.REJECTED;
this.value = reason;
setTimeout(() => {
this.callbacks.map(callback => {
try {
callback.onRejected(this.value);
} catch (error) {
callback.onRejected(error);
}
});
});
}
}
then(onFulfilled, onRejected) {
// 防止then中传入的参数为空时报错
if (typeof onFulfilled !== "function") {
onFulfilled = () => { };
}
if (typeof onRejected !== "function") {
onRejected = () => { };
}
if (this.status === PromiseA.PENDING) {
this.callbacks.push({
onFulfilled,
onRejected
});
}
if (this.status === PromiseA.FULFILLED) {
return new PromiseA((resolve, reject) => {
setTimeout(() => {
try {
let res = onFulfilled(this.value);
if (res instanceof PromiseA) {
res.then(resolve, reject);
} else {
resolve(res);
}
} catch (error) {
reject(error);
}
});
});
}
if (this.status === PromiseA.REJECTED) {
return new PromiseA((resolve, reject) => {
setTimeout(() => {
try {
let res = onRejected(this.value);
if (res instanceof PromiseA) {
res.then(resolve, reject);
} else {
reject(res);
}
} catch (error) {
reject(error);
}
});
});
}
}
static resolve(value) {
return new PromiseA((resolve, reject) => {
if (value instanceof PromiseA) {
value.then(resolve, reject);
} else {
resolve(value);
}
});
}
static reject(reason) {
return new PromiseA((resolve, reject) => {
if (reason instanceof PromiseA) {
reason.then(resolve, reject);
} else {
reject(reason);
}
});
}
}
整了Promise源码真的很累,从看源码到整理思路,再到写完博客,花了我好几天,求求各位点一个赞吧👍!!