Promise静态方法实现
实现过程中使用到的工具函数
/**
* 判断传入值是否为一个 thenable对象 (可以访问 then方法 的对象)
* @param { * } value 待判断的值
* @returns { Boolean }
*/
function isThenable(value) {
return (
!isEqual(value, null) &&
(judgmentType(value, "object") || judgmentType(value, "function")) &&
judgmentType(handleTarget.then, "function")
);
}
/**
* 判断传入值是否为一个 promise对象 实例
* @param { * } value 待判断的值
* @returns { Boolean }
*/
function isPromise(value) {
return value instanceof myPromise;
}
/**
* 判断传入值和目标值是否相等
* @param { * } value 待判断的值
* @param { * } target 目标值
* @returns { Boolean }
*/
function isEqual(value, target) {
return value === target;
}
/**
* 判断传入值和目标类型是否相等
* @param { * } value 待判断的值
* @param { * } type 目标类型
* @param { Boolean } negation 是否取反判断
* @returns { Boolean }
*/
function judgmentType(value, type, negation = false) {
if (negation) {
return typeof value !== type;
}
return typeof value === type;
}
Promise静态方法 resolve
-
Promise静态方法 resolve 可以将传入参数转换为一个Promise对象,根据参数的类型又作出不同的处理。
-
参数类型——相应处理
- 如果参数本身为一个Promise对象,则直接返回该Promise对象。
- 如果参数是一个thenable对象,则调用其then方法以及相关联的两个回调函数。
- 如果参数不符合上述情况,待返的Promise对象将以该值兑现。
- 在Promise静态方法 resolve的实现中,我们需要处理的点:根据参数类型作出相应操作、返回一个Promise对象,支持链式调用
实现
class myPromise {
....
/**
* 根据参数类型,返回对应状态的Promise对象
* @param { * } value 生成的Pormise对象结果值/返回的Promise对象
* @returns { myPromise }
*/
static resolve(value) {
if (isPromise(value)) return value // 如果参数是Promise对象直接返回
if (isThenable(value)) { // 如果参数是thenable对象,执行其then方法,并返回一个Promise对象
return new myPromise((resolve, reject) => {
value.then(resolve,reject)
})
}
// 默认返回一个 fulfilled 状态的Promise对象 结果值为传入参数值
return new myPromise((resolve, reject) => {
resolve(value)
})
}
}
// 测试
function p1() {
return new Promise((resolve, reject) => {
resolve("p1 resolve");
});
}
console.log(Promise.resolve(p1()));
console.log(Promise.resolve("aa"));
console.log(Promise.resolve([]));
console.log(Promise.resolve(new Map()));
console.log(Promise.resolve(p1));
console.log(Promise.resolve({
then(onFulfilled, onRejected) {
onFulfilled('thenable')
}
}));
Promise静态方法 reject
-
Promise静态方法 reject 无需参数类型的分类处理,统一返回一个rejected状态的Promise对象,结果值(拒因)为所传入的参数。
-
在Promise静态方法 reject的实现中,我们需要处理的点:返回一个拒绝状态的Promise对象,支持链式调用
实现
class myPromise {
....
/**
* 返回一个以参数为拒因的rejected状态的Promise对象
* @param { * } value 拒因
* @returns { myPromise }
*/
static reject(value) {
return new myPromise((resolve, reject) => {
reject(value)
})
}
}
// 测试
const p = myPromise.resolve(1);
const rejected = myPromise.reject(p);
console.log(rejected === p); // false
rejected.then(undefined,(v) => {
console.log(v === p); // true
});
myPromise.reject(new Error("失败")).then(
() => {
// 不会被调用
},
(error) => {
console.error(error); // Stacktrace
}
);
Promise静态方法 all
-
Promise静态方法 all 接收一个可迭代对象作为输入,并返回一个Promise对象,当且仅当所有的迭代值(若值不是Promise对象,需要进行转换)都被兑现时,待返的Promise对象才会被兑现(即便传入的是一个空的迭代对象)。结果值为一个包含所有兑现值的数组。如果其中一个迭代值被拒绝,则待返对象的Promise对象会被拒绝,并带有第一个被拒绝的原因。
-
在Promise静态方法 all 的实现中,我们需要处理的点:参数需要是一个可迭代对象、返回Promise对象,支持链式调用、转换不是Promise对象的迭代值为Promise对象、根据迭代处理情况决定待返Promise对象的状态。
实现
class myPromise {
....
/**
* 根据可迭代对象中迭代值的状态,决定待返Pormise对象的状态 (all fulfilled ---> fulfilled ) / (one rejected ---> rejected)
* @param { iterable } promises 可迭代对象
* @returns { myPromise }
*/
static all(promises) {
return new myPromise((resolve, reject) => {
// 获取可迭代对象的长度/遍历可迭代对象 使用的语法 均只适配与可迭代对象
// 如果在使用时产生报错 即说明用户传入的参数不是一个可迭代对象
try {
const length = [...promises].length // 获取可迭代对象的长度
const resultList = [] // 待返结果值 存储迭代值的结果
// 如果是一个空的可迭代对象 直接修改待返Promise对象的状态为 fulfilled,
if (isEqual(length, 0)) return resolve(resultList)
let count = 0 // 遍历索引
for (const promiseItem of promises) {
// 迭代值可以为任何类型,但都需要转换成Promise对象,不同的类型又有不同的转换操作
// 这里使用Promise静态方法 resolve 来进行转换
myPromise.resolve(promiseItem).then(
(result) => {
// 当前迭代值为fulfilled,存储其结果
resultList[count++] = result // 存储完毕 索引后移
// 当索引等于可迭代对象的长度时,说明所有迭代值都为fulfilled,且所有结果都存储完毕,直接修改待返对象的状态为fulfilled
isEqual(count, length) && resolve(resultList)
},
(reason) => {
// 迭代值中只要有一个rejected,就直接修改待返对象的状态为rejected
reject(reason)
}
)
}
} catch(error) {
// 用户传入的参数不是可迭代对象 直接修改待返对象的状态为rejected
reject(new TypeError("Argument is not iterable"))
}
})
}
}
// 测试
const p1 = new myPromise((resolve, reject) => {
resolve("p1 resolve");
});
const p2 = new myPromise((resolve, reject) => {
resolve("p2 resolve");
});
const thenable = {
then(onFulfilled, onRejected) {
onFulfilled("thenable resolve");
},
};
const arr = [p1, p2, thenable];
const map = new Map([
[0, p1],
[1, p2],
[2, thenable],
]);
const set = new Set([...arr]);
console.log(myPromise.all(arr));
console.log(myPromise.all(map));
console.log(myPromise.all(set));
Promise静态方法 allSettled
-
Promise静态方法 allsettled 接收一个可迭代对象作为输入,并返回一个Promise对象。当所有的迭代值(若值不是Promise对象的,需要进行转换)都已敲定时(包括传入空的可迭代对象时),待返Promise对象将被兑现,结果值为一个个结构为{ status: ‘迭代值的状态’, value: ‘迭代值的结果值’ }的对象组成的数组。
-
在Promise静态方法 allsettled 的实现中,我们需要处理的点有:参数需要是一个可迭代对象、返回Promise对象,支持链式调用、转换不是Promise对象的迭代值为Promise对象、获取每个迭代值的结果值,用于返回。
实现
class myPromise {
....
/**
* 返回一个fulfilled状态对象 结果值为一个个由 { status: '迭代值状态', value: '迭代值结果值' }结构组成的数组
* @param { iterable } promises 可迭代对象
* @returns { myPromise }
*/
static allSettled(promises) {
return new myPromise((resolve, reject) => {
try {
const length = [...promises].length
const resultList = []
if (isEqual(length, 0)) return resolve(resultList)
let count = 0
for (const promiseItem of promises) {
myPromise.resolve(promiseItem).then(
(result) => {
// 当前迭代值为fulfilled,存储其结果 存储完毕后 索引后移
resultList[count++] = {
status: 'fulfilled',
value: result
}
// 当索引等于可迭代对象的长度时,说明所有迭代值都为fulfilled,且所有结果都存储完毕,直接修改待返对象的状态为fulfilled
isEqual(count, length) && resolve(resultList)
},
(reason) => {
resultList[count++] = {
status: 'rejected',
value: reason
}
// 当索引等于可迭代对象的长度时,说明所有迭代值都为fulfilled,且所有结果都存储完毕,直接修改待返对象的状态为fulfilled
isEqual(count, length) && resolve(resultList)
}
)
}
} catch (error) {
reject(new TypeError("Argument is not iterable"))
}
})
}
}
// 测试
const p1 = new myPromise((resolve, reject) => {
resolve("p1 resolve");
});
const p2 = new myPromise((resolve, reject) => {
reject("p2 reject");
});
const thenable = {
then(onFulfilled, onRejected) {
onFulfilled("thenable resolve");
},
};
const arr = [p1, p2, thenable];
const map = new Map([
[0, p1],
[1, p2],
[2, thenable],
]);
const set = new Set([...arr]);
console.log(myPromise.allSettled(arr));
console.log(myPromise.allSettled(map));
console.log(myPromise.allSettled(set));
console.log(myPromise.allSettled("123456"));
console.log(myPromise.allSettled(123456));
Promise静态方法 any
-
Promise静态方法 any 接收一个可迭代对象作为输入,并返回一个Promise对象。当迭代值中的任何一个被兑现时(若值不是Promise对象,需要进行转换),待返回的Promise对象将会被兑现,并返回第一个兑现的值。当所有迭代值都被拒绝时(包括传递了一个空的可迭代对象),它会以一个包含拒绝原因数组的 AggregateError 拒绝
-
在Promise静态方法 any 的实现中,我们需要处理的点:参数需要是一个可迭代对象、返回Promise对象,支持链式调用、转换不是Promise对象的迭代值为Promise对象、根据迭代处理情况决定待返Promise对象的状态。
实现
class myPromise {
....
/**
* 根据可迭代对象中迭代值的状态,决定待返Pormise对象的状态 (one fulfilled ---> fulfilled ) / (all rejected ---> rejected)
* @param { iterable } promises 可迭代对象
* @returns { myPromise }
*/
static any(promises) {
return new myPromise((resolve, reject) => {
try {
const length = [...promises].length
const reasonList = [] // 待返结果值 存储迭代值的结果
// 如果是一个空的可迭代对象 直接修改待返Promise对象的状态为 rejected
if(isEqual(length, 0)) return reject(new AggregateError(reasonList,"All promises were rejected"))
let count = 0
for (const promiseItem of promises) {
myPromise.resolve(promiseItem).then(
// 迭代值中只要有一个fulfilled,就直接修改待返对象的状态为fulfilled
(result) => resolve(result),
(reason) => {
// 当前迭代值为rejected,存储其结果(拒因)
reasonList[count++] = reason // 存储完毕 索引后移
// 当索引等于可迭代对象的长度时,说明所有迭代值都为rejected,且所有结果都存储完毕,直接修改待返对象的状态为rejected
isEqual(count, length) && reject(new AggregateError(reasonList,"All promises were rejected"))
}
)
}
} catch(error) {
reject(new TypeError("Argument is not iterable"))
}
})
}
}
// 测试
const p1 = new myPromise((resolve, reject) => {
resolve("p1 resolve");
});
const p3 = new myPromise((resolve, reject) => {
setTimeout(() => {
resolve("p3 resolve");
});
});
const p2 = new myPromise((resolve, reject) => {
reject("p2 reject");
});
const thenable = {
then(onFulfilled, onRejected) {
onFulfilled("thenable resolve");
},
};
const arr = [p2, thenable, p3];
const map = new Map([
[0, p1],
[1, p2],
[2, thenable],
]);
const set = new Set([...arr]);
console.log(myPromise.any(arr));
console.log(myPromise.any(map));
console.log(myPromise.any("123456"));
console.log(myPromise.any(123));
Promise静态方法 race
-
Promise静态方法 race 接收一个可迭代对象作为输入,并返回一个Promise对象。这个返回的Promise会随着第一个Promise的敲定而敲定。
-
在Promise静态方法 race 的实现中,我们需要处理的点:参数需要是一个可迭代对象、返回Promise对象,支持链式调用、转换不是Promise对象的迭代值为Promise对象、根据第一个迭代处理情况决定待返Promise对象的状态。
实现
class myPromise {
.....
/**
* 返回一个状态由迭代值中第一个状态敲定的对象决定的Pormise对象
* @param { iterable } promises 可迭代对象
* @returns { myPromise }
*/
static race(promises) {
return new myPromise((resolve, reject) => {
try {
for (const promiseItem of promises) {
myPromise.resolve(promiseItem).then(
(result) => resolve(result),
(reason) => reject(reason)
)
}
} catch (error) {
reject(new TypeError("Argument is not iterable"))
}
})
}
}
// 测试
const p1 = new myPromise((resolve, reject) => {
resolve("p1 resolve");
});
const p3 = new myPromise((resolve, reject) => {
setTimeout(() => {
resolve("p3 resolve");
});
});
const p2 = new myPromise((resolve, reject) => {
reject("p2 reject");
});
const thenable = {
then(onFulfilled, onRejected) {
onFulfilled("thenable resolve");
},
};
const arr = [p2, thenable, p3];
const map = new Map([
[0, p1],
[1, p2],
[2, thenable],
]);
const set = new Set([...arr]);
console.log(myPromise.race(arr));
console.log(myPromise.race(map));
console.log(myPromise.race("123456"));
console.log(myPromise.race(123));
console.log(myPromise.race([]));
参考
手写实现 Promise 全部实例方法和静态方法,来看看 Promise.all、Promise.race 和 Promise.any 都是怎么实现的 – 掘金 (juejin.cn)
Promise – JavaScript | MDN (mozilla.org)