直接上代码
Promise类和then方法
class DPromise {
// 传入回调函数
constructor(executor) {
//保存状态
this.DPromiseStatus = 'pending';
//保存需要传递的值
this.DPromiseResult = null;
//保存函数,结构是数组套对象
this.callbacks = [];
const resolve = value => {
//判断状态,保证promise状态改变后不能在更改状态
if (this.DPromiseStatus === 'pending') {
this.DPromiseStatus = 'fulfilled';
this.DPromiseResult = value;
queueMicrotask(() => {
this.callbacks.forEach(item => item.onfulfilled(this.DPromiseResult));
});
}
};
//判断状态,保证promise状态改变后不能在更改状态
const reject = reason => {
if (this.DPromiseStatus === 'pending') {
this.DPromiseStatus = 'rejected';
this.DPromiseResult = reason;
queueMicrotask(() => {
this.callbacks.forEach(item => item.onrejected(this.DPromiseResult));
});
}
};
try {
//执行回调函数,参数也是回调函数
executor(resolve, reject);
} catch (e) {
//收集错误,错误信息通过reject传递
reject(e);
}
}
//then 方法
then(onfulfilled, onrejected) {
// then方法返回的也是promise对象
//onfulfilled和onrejected都需要传入函数,如果不是函数,代码运行到函数调用会出错
//如果传入非函数,则装换成函数,并将调用者的resolve参数传递下去
if (typeof onfulfilled !== 'function') {
onfulfilled = value => value;
}
//异常穿透,保证后面的catch或者then的onrejected可以捕获异常
if (typeof onrejected !== 'function') {
onrejected = reason => {
throw reason;
};
}
//获取promise对象,以便在函数内部使用
const self = this;
return new DPromise((resolve, reject) => {
// 封装一个工具函数,确定then方法中onrejected和onfulfilled回调函数的返回值
function rule(fnType) {
try {
let result = fnType(self.DPromiseResult);
// 判断 then方法回调函数的返回值是否为promise对象
//如果是,则通过promise.then方法决定新promise的状态
if (result instanceof DPromise) {
result.then(
res => resolve(res),
err => reject(err)
);
} else {
// 如果不是promise对象,则通过resolve进行包装
resolve(result);
}
} catch (e) {
//捕获异常
reject(e);
}
}
//需要判断then方法调用者的状态,如果为fulfilled则执行,onfulfilled函数,
if (this.DPromiseStatus === 'fulfilled') {
//异步调用onfulfilled方法
queueMicrotask(() => {
rule(onfulfilled);
});
}
// 如果为rejected状态,则执行onrejected函数
if (this.DPromiseStatus === 'rejected') {
//异步调用onrejected
queueMicrotask(() => {
rule(onrejected);
});
}
//如果状态为pending则将两个回调函数保存在对象中,一般如果then调用者的resolve或reject异步执行后,相应调用保存的回调函数
if (this.DPromiseStatus === 'pending') {
this.callbacks.push({
onfulfilled() {
rule(onfulfilled);
},
onrejected() {
rule(onrejected);
},
});
}
});
}
}
catch和finally
catch(onrejected) {
//相当于then方法onrejected的语法糖
return this.then(undefined, onrejected);
}
finally(onfinally) {
// 调用then方法,在最后不管哪种状态,都执行回调函数
this.then(
() => {
onfinally();
},
() => {
onfinally();
}
);
}
resolve和reject
static resolve(value) {
return new DPromise((resolve, reject) => {
//判断一下value值是否为promise对象,跟前面then方法中的工具函数一样
if (value instanceof DPromise) {
value.then(
res => resolve(res),
err => reject(err)
);
} else {
resolve(value);
}
});
}
static reject(reason) {
return new DPromise((resolve, reject) => {
reject(reason);
});
}
all和allSettled
static all(promises) {
return new DPromise((resolve, reject) => {
let count = 0;
let result = [];
for (let i = 0; i < promises.length; i++) {
promises[i].then(
res => {
count++;
// 通过下标值可以确保返回结果的顺序不会被打乱
result[i] = res;
if (count === promises.length) {
resolve(result);
}
},
err => {
reject(err);
}
);
}
});
}
static allSettled(promises) {
//返回所有执行结果
return new DPromise((resolve, reject) => {
const result = [];
let count = 0;
promises.forEach((promise, index) => {
promise.then(
res => {
count++;
result[index] = { status: 'fulfilled', value: res };
if (count === promises.length) {
resolve(result);
}
},
err => {
count++;
result[index] = { status: 'rejected', value: err };
if (count === promises.length) {
resolve(result);
}
}
);
});
});
}
为什么使用变量计数而不是数组下标值?
写到all方法突然产生的疑惑,经过思考->不能使用result.length来判断判断promises是否遍历完成。
- 举个例子:如果promises中所有的promise对象,resolve外都包裹一层setTimeout定时器,而最后一个的定时器时间最短,那么遍历开始,进入.then方法,判断为pending状态,然后将then的onfulfilled回调函数保存在实例对象中,等到定时器结束,最后一个promise先执行resolve(),满足了result.length ===promises.length,返回的结果就是[empty,empty,empty,...,res],只有最后一个索引有值,其他全是空的,经过测试也证实我的想法,如果使用数组下标值来判断,确实会导致返回的结果是由数组最后一个值的执行时机决定的。 如下错误代码验证
static all(promises) {
return new HYPromise((resolve, reject) => {
const values = [];
promises.forEach((promise, index) => {
promise.then(
res => {
values[index] = res;
if (values.length === promises.length) {
resolve(values);
}
},
err => {
reject(err);
}
);
});
});
}
//测试代码
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1111);
}, 3000);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2222);
}, 2000);
});
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(3333);
}, 1000);
});
HYPromise.all([p1, p2, p3]).then(res => {
console.log('res:', res);
});
Promise.all([p1, p2, p3]).then(res => {
console.log('res:', res);
});
//打印结果
res: (3) [empty × 2, 3333]
res: (3) [1111, 2222, 3333]
race 和any
static race(promises) {
return new DPromise((resolve, reject) => {
promises.forEach(promise => {
promise.then(
res => resolve(res),
err => reject(err)
);
});
});
}
static any(promises) {
//返回最先完成的resolve,或者返回全部的reject
return new DPromise((resolve, reject) => {
const result = [];
let count = 0;
promises.forEach((promise, index) => {
promise.then(
res => {
resolve(res);
},
err => {
count++;
result[index] = err;
if (count === promises.length) {
reject(new AggregateError(result));
}
}
);
});
});
}
完整代码
class DPromise {
// 传入回调函数
constructor(executor) {
//保存状态
this.DPromiseStatus = 'pending';
//保存需要传递的值
this.DPromiseResult = null;
//保存函数,结构是数组套对象
this.callbacks = [];
const resolve = value => {
//判断状态,保证promise状态改变后不能在更改状态
if (this.DPromiseStatus === 'pending') {
this.DPromiseStatus = 'fulfilled';
this.DPromiseResult = value;
queueMicrotask(() => {
this.callbacks.forEach(item => item.onfulfilled(this.DPromiseResult));
});
}
};
//判断状态,保证promise状态改变后不能在更改状态
const reject = reason => {
if (this.DPromiseStatus === 'pending') {
this.DPromiseStatus = 'rejected';
this.DPromiseResult = reason;
queueMicrotask(() => {
this.callbacks.forEach(item => item.onrejected(this.DPromiseResult));
});
}
};
try {
//执行回调函数,参数也是回调函数
executor(resolve, reject);
} catch (e) {
//收集错误,错误信息通过reject传递
reject(e);
}
}
//then 方法
then(onfulfilled, onrejected) {
// then方法返回的也是promise对象
//onfulfilled和onrejected都需要传入函数,如果不是函数,代码运行到函数调用会出错
//如果传入非函数,则装换成函数,并将调用者的resolve参数传递下去
if (typeof onfulfilled !== 'function') {
onfulfilled = value => value;
}
//异常穿透,保证后面的catch或者then的onrejected可以捕获异常
if (typeof onrejected !== 'function') {
onrejected = reason => {
throw reason;
};
}
//获取promise对象,以便在函数内部使用
const self = this;
return new DPromise((resolve, reject) => {
// 封装一个工具函数,确定then方法中onrejected和onfulfilled回调函数的返回值
function rule(fnType) {
try {
let result = fnType(self.DPromiseResult);
// 判断 then方法回调函数的返回值是否为promise对象
//如果是,则通过promise.then方法决定新promise的状态
if (result instanceof DPromise) {
result.then(
res => resolve(res),
err => reject(err)
);
} else {
// 如果不是promise对象,则通过resolve进行包装
resolve(result);
}
} catch (e) {
//捕获异常
reject(e);
}
}
//需要判断then方法调用者的状态,如果为fulfilled则执行,onfulfilled函数,
if (this.DPromiseStatus === 'fulfilled') {
//异步调用onfulfilled方法
queueMicrotask(() => {
rule(onfulfilled);
});
}
// 如果为rejected状态,则执行onrejected函数
if (this.DPromiseStatus === 'rejected') {
//异步调用onrejected
queueMicrotask(() => {
rule(onrejected);
});
}
//如果状态为pending则将两个回调函数保存在对象中,一般如果then调用者的resolve或reject异步执行后,相应调用保存的回调函数
if (this.DPromiseStatus === 'pending') {
this.callbacks.push({
onfulfilled() {
rule(onfulfilled);
},
onrejected() {
rule(onrejected);
},
});
}
});
}
catch(onrejected) {
//相当于then方法onrejected的语法糖
return this.then(undefined, onrejected);
}
finally(onfinally) {
// 调用then方法,在最后不管哪种状态,都执行回调函数
this.then(
() => {
onfinally();
},
() => {
onfinally();
}
);
}
static resolve(value) {
return new DPromise((resolve, reject) => {
//判断一下value值是否为promise对象,跟前面then方法中的工具函数一样
if (value instanceof DPromise) {
value.then(
res => resolve(res),
err => reject(err)
);
} else {
resolve(value);
}
});
}
static reject(reason) {
return new DPromise((resolve, reject) => {
reject(reason);
});
}
static all(promises) {
return new DPromise((resolve, reject) => {
//为什么使用变量计数而不是result.length来判断判断promises是否遍历完成,举个例子:如果promises中所有的promise对象,resolve外都包裹一层setTimeout定时器,而最后一个的定时器时间最短,那么遍历开始,进入.then方法,判断为pending状态,然后将then的onfulfilled回调函数保存在实例对象中,等到定时器结束,最后一个promise先执行resolve(),满足了result.length ===promises.length,返回的结果就是[empty,empty,empty,...,res],只有最后一个索引有值,其他全是空的
let count = 0;
let result = [];
for (let i = 0; i < promises.length; i++) {
promises[i].then(
res => {
count++;
// 通过下标值可以确保返回结果的顺序不会被打乱
result[i] = res;
if (count === promises.length) {
resolve(result);
}
},
err => {
reject(err);
}
);
}
});
}
static allSettled(promises) {
//返回所有执行结果
return new DPromise((resolve, reject) => {
const result = [];
let count = 0;
promises.forEach((promise, index) => {
promise.then(
res => {
count++;
result[index] = { status: 'fulfilled', value: res };
if (count === promises.length) {
resolve(result);
}
},
err => {
count++;
result[index] = { status: 'rejected', value: err };
if (count === promises.length) {
resolve(result);
}
}
);
});
});
}
static race(promises) {
return new DPromise((resolve, reject) => {
promises.forEach(promise => {
promise.then(
res => resolve(res),
err => reject(err)
);
});
});
}
static any(promises) {
//返回最先完成的resolve,或者返回全部的reject
return new DPromise((resolve, reject) => {
const result = [];
let count = 0;
promises.forEach((promise, index) => {
promise.then(
res => {
resolve(res);
},
err => {
count++;
result[index] = err;
if (count === promises.length) {
reject(new AggregateError(result));
}
}
);
});
});
}
}
//测试代码
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1111);
}, 3000);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2222);
}, 2000);
});
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(3333);
}, 1000);
});
DPromise.all([p1, p2, p3]).then(
res => {
console.log('res:', res);
},
err => {
console.log('err:', err);
}
);
Promise.all([p1, p2, p3]).then(
res => {
console.log('res:', res);
},
err => {
console.log('err:', err);
}
);