之前的部分可以看上一篇手写Promise(一)
catch和finally
我们经常遇到无论Promise最后状态如何都需要进行某些操作的情况。这时候就需要使用finally,因为finally方法传入的回调并不关心当前Promise的状态和结果,也不会改变返回的Promise的状态和结果,所以一定不要用then(onSettled, onSettled)来实现。
catch(onRejected) {
return this.then(null, onRejected);
}
finally(onSettled) {
if (typeof onSettled !== "function") {
return this.then();
}
return this.then(
(data) => {
onSettled();
return data;
},
(reason) => {
onSettled();
throw reason;
}
);
}
静态方法resolve和reject
resolve需要分情况讨论:
- 如果参数就是一个ES6的Promise对象,那么resolve会直接返回这个对象。
- 如果参数是一个thenable对象(可以沿用之前的isPromise来判断),会先调用它的then方法,将其转成一个Promise对象返回
- 不满足1和2的,返回一个新的Promise对象,状态为fulfilled,值为传入的参数
reject只会返回一个新的Promise对象,状态为rejected,值为传入的参数
static resolve(value) {
if (value && value instanceof Promise) {
return value;
} else if (isPromise(value)) {
return new Promise((resolve) => {
value.then(resolve);
});
} else {
return new Promise((resolve) => resolve(value));
}
}
static reject(value) {
return new Promise((resolve, reject) => reject(value));
}
静态方法all,allSettled和race
实现之前先看一个简单的例子
Promise.all([
Promise.resolve(1),
1,
2,
]).then(
(data) => {
console.log("data: ", data);
},
(reason) => {
console.log("reason: ", reason);
}
);
输出结果:
data: [1, 1, 2]
所以不能直接调用then方法,而应该调用Promise.resolve()
static all(promises) {
return new Promise((resolve, reject) => {
const results = [];
const total = promises.length;
if (total === 0) {
resolve(results);
}
let count = 0;
promises.forEach((promise, index) => {
Promise.resolve(promise).then(
(data) => {
count++;
results[index] = data;
if (count === total) {
resolve(results);
}
},
(reason) => {
reject(reason);
}
);
});
});
}
static allSettled(promises) {
return new Promise((resolve) => {
const results = [];
const total = promises.length;
if (total === 0) {
resolve(results);
}
let count = 0;
promises.forEach((promise, index) => {
Promise.resolve(promise)
.then(
(value) => {
results[index] = { status: "fulfilled", value };
},
(reason) => {
results[index] = { status: "rejected", reason };
}
)
.finally(() => {
count++;
if (count === total) {
resolve(results);
}
});
});
});
}
static race(promises) {
return new Promise((resolve, reject) => {
for (const promise of promises) {
Promise.resolve(promise).then(resolve, reject);
}
});
}
第五版实现
function isPromise(value) {
return (
!!value &&
(typeof value === "object" || typeof value === "function") &&
typeof value.then === "function"
);
}
function queueMicrotaskPolyfill(callback) {
let textNode = document.createTextNode("");
let counter = 0;
const observer = new MutationObserver(() => {
callback();
observer.disconnect();
});
observer.observe(textNode, { characterData: true });
textNode.data = String(counter++);
}
class Promise {
constructor(executor) {
this.state = "pending";
this.value = null;
this.handlers = [];
try {
executor(this._resolve.bind(this), this._reject.bind(this));
} catch (error) {
console.error(error);
this._reject(error);
}
}
static resolve(value) {
if (value && value instanceof Promise) {
return value;
} else if (isPromise(value)) {
return new Promise((resolve) => {
value.then(resolve);
});
} else {
return new Promise((resolve) => resolve(value));
}
}
static reject(value) {
return new Promise((resolve, reject) => reject(value));
}
static all(promises) {
return new Promise((resolve, reject) => {
const results = [];
const total = promises.length;
if (total === 0) {
resolve(results);
}
let count = 0;
promises.forEach((promise, index) => {
Promise.resolve(promise).then(
(data) => {
count++;
results[index] = data;
if (count === total) {
resolve(results);
}
},
(reason) => {
reject(reason);
}
);
});
});
}
static allSettled(promises) {
return new Promise((resolve) => {
const results = [];
const total = promises.length;
if (total === 0) {
resolve(results);
}
let count = 0;
promises.forEach((promise, index) => {
Promise.resolve(promise)
.then(
(value) => {
results[index] = { status: "fulfilled", value };
},
(reason) => {
results[index] = { status: "rejected", reason };
}
)
.finally(() => {
count++;
if (count === total) {
resolve(results);
}
});
});
});
}
static race(promises) {
return new Promise((resolve, reject) => {
for (const promise of promises) {
Promise.resolve(promise).then(resolve, reject);
}
});
}
then(onFulfilled, onRejected) {
return new Promise((resolve, reject) => {
this._pushHandler(onFulfilled, onRejected, resolve, reject);
this._executeHandlers();
});
}
catch(onRejected) {
return this.then(null, onRejected);
}
finally(onSettled) {
if (typeof onSettled !== "function") {
return this.then();
}
return this.then(
(data) => {
onSettled();
return data;
},
(reason) => {
onSettled();
throw reason;
}
);
}
_changeState(newState, value) {
if (this.state !== "pending") {
return;
}
this.state = newState;
this.value = value;
this._executeHandlers();
}
_resolve(data) {
if (isPromise(data)) {
data.then.call(
data,
this._resolve.bind(this),
this._reject.bind(this)
);
return;
}
this._changeState("fulfilled", data);
}
_reject(reason) {
this._changeState("rejected", reason);
}
_pushHandler(onFulfilled, onRejected, resolve, reject) {
this.handlers.push({
onFulfilled: onFulfilled || null,
onRejected: onRejected || null,
resolve: resolve,
reject: reject,
handled: false,
});
}
_executeHandlers() {
if (this.state === "pending") {
return;
}
this.handlers.forEach((handler) => this._handle(handler));
}
_handle(handler) {
if (handler.handled === true) {
return;
}
queueMicrotaskPolyfill(() => {
try {
let result;
if (this.state === "fulfilled") {
result =
typeof handler.onFulfilled === "function"
? handler.onFulfilled(this.value)
: this.value;
handler.resolve(result);
} else if (this.state === "rejected") {
if (typeof handler.onRejected === "function") {
result = handler.onRejected(this.value);
handler.resolve(result);
} else {
handler.reject(this.value);
}
}
} catch (error) {
console.error(error);
handler.reject(error);
} finally {
handler.handled = true;
}
});
}
}