前言
- 写
Promise之前需要知道它是什么
MDN
Promise对象表示异步操作最终的完成(或失败)以及其结果值。Promise对象表示异步操作最终的完成(或失败)以及其结果值。
- 知道
Promise是什么了之后需要知道它怎么使用 还有它的一些静态方法
实现
简单的使用方法:
const promise = new Promise((resolve, reject) => {
const res = Math.floor(Math.random() * 2);
if (res) {
resolve(res);
} else {
reject(res);
}
})
console.log(promise);
promise.then(value => {
console.log(value);
}).catch(reason => {
console.log(reason);
}).finally(() => {
console.log('finally');
});
在浏览器执行这段代码后发现其中需要注意的点是
Promise中的状态- PENDING
- 初始化的状态
- FULFILLED
- 执行
resolve后的状态
- 执行
- REJECTED
- 执行
reject后的状态
- 执行
- PENDING
- 传入的立即执行方法
excutor- 正确执行时的
resolve - 错误时执行的
reject
- 正确执行时的
- 实例中的三个异步方法
- then
- catch
- finally
- 链式调用
实现then catch finally resolve reject
- 确定
Promise中的三种状态以及立即执行方法
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
constructor(executor) {
this.status = PENDING;
// 成功值和失败的原因在初始化时都为undefined
this.value = undefined;
this.reason = undefined;
executor(this.reslove, this.reject);
}
resolve(value) {
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
}
}
reject(reason) {
if (this.status === PENDING) {
this.status === REJECTED;
this.reason = reason;
}
}
}
- 但是根据MDN文档显示
Promise中有resolve和reject两个静态方法 并且返回一个Promise实例 具体详见MDN
Promise.resolve() - JavaScript | MDN (mozilla.org)
Promise.reject() - JavaScript | MDN (mozilla.org)
class Promise {
constructor(executor) {
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
executor(this.#privateResolve, this.#privateReject);
}
#privateResolve(value) {
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
}
}
#privateReject(reason) {
if (this.status === PENDING) {
this.status === REJECTED;
this.reason = reason;
}
}
// value 可以是一个任意值或者是一个Promise
// 静态方法返回一个状态FULFILLED的Promise
static resolve(value) {
return value instanceof Promise
? value
: new Promise((resolve) => resolve(value));
}
// 返回一个状态是REJECTED的Promise
static reject(reason) {
return new Promise((resolve, reject) => reject(reason));
}
}
- 实现
thencatchfinally方法
- 三个方法都是异步方法 需要将后续执行方法保存, 等异步执行完毕后继续执行。
- 三个方法都是链式调用 需要返回一个Promise实例 (暂时不实现)
finally- 状态改变后执行 如果状态不变则不执行
class Promise {
constructor(executor) {
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
this.fulfilledCallback = undefined;
this.rejectedCallback = undefined;
this.onFinallyCallback = undefined;
executor(this.#privateResolve, this.#privateReject);
}
#privateResolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
this.fulfilledCallback?.(value);
this.onFinallyCallback?.();
}
}
#privateReject = (reason) => {
if (this.status === PENDING) {
this.status === REJECTED;
this.reason = reason;
this.rejectedCallback?.(reason);
this.onFinallyCallback?.();
}
}
// 在执行onfulfilled方法时需要进行类型检查 如果类型不对或者没传 则修改为默认方法
privateCheckOnFulFilled(onFulfilled) {
return typeof onFulfilled === 'function' ? onFulfilled : (value) => value;
}
// 执行onreject方法前也需要进行类型检查 如果未通过则改为默认方法
privateCheckOnRejected(onRejected) {
return typeof onRejected === 'function'
? onRejected
: (reason) => {
throw reason;
};
}
// finally方法也是如此 默认方法为空方法
privateCheckOnFinally(onFinally) {
return typeof onFinally === 'function' ? onFinally : () => { };
}
...
then(onFulfilled, onRejected) {
onFulfilled = this.privateCheckOnFulFilled(onFulfilled);
onRejected = this.privateCheckOnRejected(onRejected);
// 根据当前状态判定应该异步执行还是‘同步’执行
switch (this.status) {
case FULFILLED:
this.fulfilledCallback(this.value);
break;
case REJECTED:
this.rejectedCallback(this.reason);
break;
case PENDING:
default:
this.fulfilledCallback = onFulfilled;
this.rejectedCallback = onRejected;
}
}
catch(onRejected) {
onRejected = this.privateCheckOnRejected(onRejected);
switch (this.status) {
case REJECTED:
onRejected(this.reason);
break;
case FULFILLED:
break;
case PENDING:
this.rejectedCallback = onRejected;
}
}
finally(onFinally) {
onFinally = this.privateCheckOnFinally(onFinally);
switch (this.status) {
case PENDING:
this.onFinallyCallback = onFinally;
break;
case REJECTED:
case FULFILLED:
default:
onFinally();
}
}
}
- 实现
then的链式调用
- 上一个
then方法中return的值是下一个then方法中的参数
class Promise {
...
then(onFulfilled, onRejected) {
onFulfilled = this.privateCheckOnFulFilled(onFulfilled);
onRejected = this.privateCheckOnRejected(onRejected);
const promise = new Promise((resolve, reject) => {
let result = undefined;
let reason = undefined;
try {
switch (this.status) {
case FULFILLED:
result = this.fulfilledCallback(this.value);
resolve(result);
break;
case REJECTED:
reason = this.rejectedCallback(this.reason);
reject(err);
break;
case PENDING:
default:
this.fulfilledCallback = (value) => {
try {
const result = onFulfilled(value);
resolve(result);
} catch(reson) {
reject(reson);
}
};
this.rejectedCallback = onRejected;
}
} catch(err) {
reject(err);
}
})
return promise;
}
...
}
- 实现
catch和finally的链式调用
catch的注意事项- 错误传递当出现错误后 错误会一直向下寻找到可以执行
onReject方法的地方 catch是 Promise.prototype.then(undefined, onRejected) 的一种简写形式
- 错误传递当出现错误后 错误会一直向下寻找到可以执行
finally不会接收参数finally类似于调用 Promise.prototype.then(onFinally, onFinally)finally不接收参数- 不会改变
promise的状态- 与
Promise.resolve(2).then(() => 77, () => {})不同,它返回一个最终会兑现为值77的 promise,而Promise.resolve(2).finally(() => 77)返回一个最终兑现为值2的 promise。 - 类似地,与
Promise.reject(3).then(() => {}, () => 88)不同,它返回一个最终兑现为值88的 promise,而Promise.reject(3).finally(() => 88)返回一个最终以原因3拒绝的 promise。
- 与
class Promise {
catch(onRejected) {
return this.then(undefined, onRejected);
}
finally(onFinally) {
onFinally = this.privateCheckOnFinally(onFinally);
return this.then(
// 不能修改当前promise的状态
(value) => Promise.resolve(onFinally()).then(() => value),
(reason) =>
Promise.resolve(onFinally()).then(() => {
throw reason;
})
);
}
}
其他静态方法
Promise.all()
Promise.all的使用方法以及规则
- 返回一个
promise - 如果传入的
promise迭代 中只要有一个状态变为REJECTED,则Promise.all的状态也变为REJECTED
class Promise {
...
// all的入参是一个可迭代对象
static all(iterable) {
return new Promise((resolve, reject) => {
const promiseArray = Array.from(iterable);
const size = promiseArray.length;
const res = new Array(size).fill();
let index = 0;
for (let i = 0; i < size; i++) {
Promise.resolve(promiseArray[i]).then(value => {
Promise.resolve(promiseArray[i]).then(value => {
res[i] = value;
index++;
if (index === size) {
resolve(res);
}
},
reason => {
reject(reason);
})
}
})
}
}
Promise.allSettled()
Promise.allSettled的使用方法以及规则
- 和all基本相同 不同的是返回值和不论迭代结果是
REJECTED还是FULFILLED
class Promise {
...
static allSettled(iterable) {
return new Promise3((resolve, reject) => {
const promiseArray = Array.from(iterable);
const size = promiseArray.length;
const res = new Array(size).fill();
let index = 0;
for (let i = 0; i < size; i++) {
Promise.resolve(promiseArray[i]).then(value => {
Promise3.resolve(promiseArray[i]).then(value => {
res[i] = {
status: 'fulfilled',
value
};
index++;
if (index === size) {
resolve(res);
}
},
reason => {
res[i] = {
status: 'rejected',
reason
};
index++;
if (index === size) {
resolve(res);
}
})
}
})
}
}
Promise.race()
Promise.race的使用方法以及规则
- 取最快结果 不管结果状态是什么
- 参数是一个
promise的可迭代对象
class Promise {
...
static race(iterable) {
return new Promise((resolve, reject) => {
const promiseArray = Array.from(iterable);
const size = promiseArray.length;
for (let i = 0; i < size; i++) {
promiseArray[i].then(value => {
resolve(value);
},
reason => {
reject(reason);
})
}
})
}
}
Promise.any()
Promise.any的使用方法以及规则
- 和
race相似 不同的是只返回状态为FULFILLED的值 如果全部是REJECTED则返回一个错误
class Promise {
...
static any(iterable) {
return new Promise((resolve, reject) => {
const promiseArray = Array.from(iterable);
const size = promiseArray.length;
const errRes = new Array(size);
let index = 0;
for (let i = 0; i < size; i++) {
promiseArray[i].then(value => {
resolve(value);
},
reason => {
index++;
if (index === size) {
reject('AggregateError: All promises were rejected');
}
})
}
})
}
}
总结
MDN nb
更完善的可以参照 - core-js 中 Promise 的 Polyfill
完整代码
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
constructor(executor) {
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
this.fulfilledCallback = undefined;
this.rejectedCallback = undefined;
this.onFinallyCallback = undefined;
executor(this.#privateResolve, this.#privateReject);
}
#privateResolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
this.fulfilledCallback?.(value);
this.onFinallyCallback?.();
}
}
#privateReject = (reason) => {
if (this.status === PENDING) {
this.status === REJECTED;
this.reason = reason;
this.rejectedCallback?.(reason);
this.onFinallyCallback?.();
}
}
#checkOnFulFilled(onFulfilled) {
return typeof onFulfilled === 'function' ? onFulfilled : (value) => value;
}
#checkOnRejected(onRejected) {
return typeof onRejected === 'function'
? onRejected
: (reason) => {
throw reason;
};
}
#checkOnFinally(onFinally) {
return typeof onFinally === 'function' ? onFinally : () => { };
}
static resolve(value) {
return value instanceof Promise
? value
: new Promise((resolve) => resolve(value));
}
static reject(reason) {
return new Promise((resolve, reject) => reject(reason));
}
then(onFulfilled, onRejected) {
onFulfilled = this.#checkOnFulFilled(onFulfilled);
onRejected = this.#checkOnRejected(onRejected);
const promise = new Promise((resolve, reject) => {
let result = undefined;
let reason = undefined;
try {
switch (this.status) {
case FULFILLED:
result = this.fulfilledCallback(this.value);
resolve(result);
break;
case REJECTED:
reason = this.rejectedCallback(this.reason);
reject(err);
break;
case PENDING:
default:
this.fulfilledCallback = (value) => {
try {
const result = onFulfilled(value);
resolve(result);
} catch (reson) {
reject(reson);
}
};
this.rejectedCallback = onRejected;
}
} catch (err) {
reject(err);
}
})
return promise;
}
catch(onRejected) {
return this.then(undefined, onRejected);
}
finally(onFinally) {
onFinally = this.#checkOnFinally(onFinally);
return this.then(
(value) => Promise.resolve(onFinally()).then(() => value),
(reason) =>
Promise.resolve(onFinally()).then(() => {
throw reason;
})
);
}
static all(iterable) {
return new Promise((resolve, reject) => {
const promiseArray = Array.from(iterable);
const size = promiseArray.length;
const res = new Array(size);
let index = 0;
for (let i = 0; i < size; i++) {
Promise.resolve(promiseArray[i]).then(value => {
res[i] = value;
index++;
if (index === size) {
resolve(res);
}
},
reason => {
reject(reason);
})
}
})
}
static allSettled(iterable) {
return new Promise((resolve, reject) => {
const promiseArray = Array.from(iterable);
const size = promiseArray.length;
const res = new Array(size);
let index = 0;
for (let i = 0; i < size; i++) {
Promise.resolve(promiseArray[i]).then(value => {
res[i] = {
status: 'fulfilled',
value
};
index++;
if (index === size) {
resolve(res);
}
},
reason => {
res[i] = {
status: 'rejected',
reason
};
index++;
if (index === size) {
resolve(res);
}
})
}
})
}
static race(iterable) {
return new Promise((resolve, reject) => {
const promiseArray = Array.from(iterable);
const size = promiseArray.length;
for (let i = 0; i < size; i++) {
promiseArray[i].then(value => {
resolve(value);
},
reason => {
reject(reason);
})
}
})
}
static any(iterable) {
return new Promise((resolve, reject) => {
const promiseArray = Array.from(iterable);
const size = promiseArray.length;
const errRes = new Array(size);
let index = 0;
for (let i = 0; i < size; i++) {
promiseArray[i].then(value => {
resolve(value);
},
reason => {
index++;
if (index === size) {
reject('AggregateError: All promises were rejected');
}
})
}
})
}
}