首先我们了解一下Promise A+ 规范 promisesaplus.com.cn/ ,这里解释一下 Promise A+ 规范不是我们常说的Promise
Promise A+ 规范
是一个社区制定的规范早于ES6 Promise
之前,定义了 Promise 的行为和接口ES6 Promise
是 ECMAScript 2015(ES6)标准的一部分,实现了Promise A+ 规范
,但有一些额外的功能和细节上的差异
Promise A+ 规范 的一些关键点
-
构造函数
Promise
构造函数接受一个执行器函数(executor function),该函数立即执行。- 执行器函数接受两个参数:
resolve
和reject
,分别用于将 Promise 标记为成功或失败。
-
状态
- 一个 Promise 有三种状态
- pending(进行中):初始状态,既不是成功也不是失败
- fulfilled(已成功):操作成功完成
- rejected(已失败):操作失败
状态不可逆
一旦从 pending 状态变为 fulfilled 或 rejected,状态就不会再改变
-
实例方法
-then(onFulfilled, onRejected)
:Promise A+ 规范里面只有这一个方法
,其他的比如下面的 catch finally 都是ES6的Promise新增的。
-catch(onRejected)
:相当于then(null, onRejected)
,用于捕获前面链中的错误。
-finally(onFinally)
:无论 Promise 成功还是失败,都会执行onFinally
回调。 -
静态方法
-Promise.resolve(value)
:返回一个以给定值成功完成的 Promise -Promise.reject(reason)
:返回一个以给定原因失败的 Promise。
-Promise.all(iterable)
:等待所有 Promise 完成,如果所有 Promise 都成功,则返回一个包含所有结果的数组;如果有任何一个 Promise 失败,则返回第一个失败的 Promise 的原因。
-Promise.race(iterable)
:等待第一个完成的 Promise,并返回其结果或原因。 -
错误处理
- 使用catch
方法可以更方便地处理错误。
- 如果没有使用catch
处理错误,错误会被抛出到全局上下文(如浏览器的window.onerror
)。
接下来我们由浅入深,来实现一个符合 Promise A+ 规范
的构造函数
一. 构造函数实现,不包含then方法
// 初始化状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class MyPromise {
// # 声明私有属性避免外部调用
#state = PENDING;
#value;
constructor(executor) {
const resolve = (value) => {
this.#setState(FULFILLED, value);
};
const reject = (error) => {
this.#setState(REJECTED, error);
};
// 错误捕获,注意这里捕获不到异步的错误,原生Promise也捕获不到
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
#setState(state, value) {
if (this.#state !== PENDING) return; // 状态是不可逆的
this.#state = state;
this.#value = value;
}
}
- 验证state,value的值是否正确
- state是否不可逆
- 错误是否捕获到
const p = new MyPromise((resolve, reject) => {
resolve(1);
throw new Error(2222)
});
console.log("p", p);
二. 实现then方法
then方法 是Promise A+ 规范里面的核心,也只有这一个方法,我们看下先怎么使用
const p = new Promise((resolve, reject) => {
resolve("success");
reject("error");
});
p.then(
(res) => {
// 成功的回调
console.log("res", res);
},
(error) => {
// 失败的回调
console.log("error", error);
}.then(
// 支持链式调用,而且在链式调用过程中状态也是可以改变的,比如发生错误调用catch捕获
(res) => {
console.log("第二次 res", res);
},
(error) => {
console.log("第二次 error", error);
}
)
);
实现
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class MyPromise {
// # 声明私有属性避免外部调用
#state = PENDING;
#value;
#handlers = [];
constructor(executor) {
const resolve = (value) => {
this.#setState(FULFILLED, value);
};
const reject = (error) => {
this.#setState(REJECTED, error);
};
// 错误捕获,注意这里捕获不到异步的错误,原生Promise也捕获不到
try {
// 接受一个执行器函数该函数立即执行
// 执行器函数接受两个参数:resolve 和 reject,分别用于将 Promise 标记为成功或失败
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
#setState(state, value) {
if (this.#state !== PENDING) return; // 状态是不可逆的
this.#state = state;
this.#value = value;
this.#ranTask();
}
#ranTask() {
if (this.#state !== PENDING) {
this.#handlers.forEach((cb) => cb());
this.#handlers = []; // 执行完清空
}
}
then(onFulfilled, onRejected) {
// 支持链式调用
return new MyPromise((resolve, reject) => {
// 保存每次then调用时候的回调函数,状态改变的时候一起执行
this.#handlers.push(() => {
try {
if (this.#state === FULFILLED) {
// 链式调用的返回值
const res = onFulfilled(this.#value);
resolve(res);
}
if (this.#state === REJECTED) {
// 链式调用的返回值,注意这里也是resolve,返回的还是成功的promise
const error = onRejected(this.#value);
resolve(error);
}
} catch (error) {
reject(error);
}
});
this.#ranTask();
});
}
}
// 测试链式调用
const p = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 10);
});
p.then(
(res) => {
console.log("第一次 res", res);
},
(error) => {
console.log("第一次 error", error);
}
);
p.then(
(res) => {
console.log("第二次 res", res);
return 3;
},
(error) => {
console.log("第二次 error", error);
}
).then((res) => {
console.log("第三次 res", res);
});
三. 完善then方法
上面then方法还遗留一些问题,我们来解决一下
- 如果 onFulfilled 不是函数且 promise1 成功完成, promise2 必须成功完成并返回相同的值
- then方法是异步调用
- 如果 then方法返回值是一个 promiseLike对象(有 then 方法且看上去像一个 promise),promiseLike对象 的完成值,而不是这个 promiseLike对象本身
完善之前我们先写一个 isPromiseLike 函数
- 如果一个值的类型为 object 或者 function
- 该值还存在一个then方法
- 该值就是一个 PromiseLike 对象
function isPromiseLike(obj) {
// 对象有then方法
return typeof obj?.then === "function";
}
现在开始完善then方法
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class MyPromise {
// # 声明私有属性避免外部调用
#state = PENDING;
#value;
#handlers = [];
constructor(executor) {
const resolve = (value) => {
this.#setState(FULFILLED, value);
};
const reject = (error) => {
this.#setState(REJECTED, error);
};
// 错误捕获,注意这里捕获不到异步的错误,原生Promise也捕获不到
try {
// 接受一个执行器函数该函数立即执行
// 执行器函数接受两个参数:resolve 和 reject,分别用于将 Promise 标记为成功或失败
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
#setState(state, value) {
if (this.#state !== PENDING) return; // 状态是不可逆的
this.#state = state;
this.#value = value;
this.#ranTask();
}
#ranTask() {
// 加入微任务队列,考虑兼容问题可以自己在写一个方法
queueMicrotask(() => {
if (this.#state !== PENDING) {
this.#handlers.forEach((cb) => cb());
this.#handlers = []; // 执行完清空
}
});
}
then(onFulfilled, onRejected) {
// 支持链式调用
return new MyPromise((resolve, reject) => {
// 保存每次then调用时候的回调函数,状态改变的时候一起执行
this.#handlers.push(() => {
try {
const cb = this.#state === FULFILLED ? onFulfilled : onRejected;
// 如果 onFulfilled 不是函数
const res = typeof cb === "function" ? cb(this.#value) : this.#value;
if (isPromiseLike(res)) {
res.then(resolve, reject);
} else {
resolve(res);
}
} catch (error) {
reject(error);
}
});
this.#ranTask();
});
}
}
// 测试链式调用
const p = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 10);
});
// 测试 onFulfilled 不是函数
p.then(null, (error) => {
console.log("第一次 error", error);
}).then((res) => {
console.log("第一次 res", res);
});
// then 返回 promiseLike对象
const p1 = p.then((res) => {
return new MyPromise((resolve, reject) => {
resolve(2);
// reject(2);
});
});
p1.then((res) => {
console.log("p1 ===", res);
},(error) => {
console.log("p1 error ===", error);
});