在ES6中推出了新的类方法,用于解决跨域之间的参数传递----Promise。
Promise的创建时需要传入两个回调函数(Resolve、Reject),并且函数在Promise对象被创建时立马调用,当程序代码运行结果满足预设的条件时,回调Resolve方法,当程序代码的运行结果不满足预设条件时,回调Reject方法,返回Promise对象,对象中有then、catch、finally方法,当用户对Promise对象调用then方法时,传入两个回调函数,第一个回调函数对应Promise内Resolve函数被调用时执行,第二个函数对应Promise内Reject函数被调用时执行,同时调用then方法时返回新的Promise对象,对应回调函数的返回值赋值给新Promise对象的value,实现链式调用,若在then链式前Promise对象的Reject函数被调用,则将Promise的状态交由then新返回的Promise管理。
同时Promise还提供了Catch方法,用于捕获Reject被调用时回调的方法,同时返回新的Promise对象,并将回调函数执行的结果传递给新Promise对象的value,如果then中有对Reject函数进行了回调,则catch方法不会执行回调函数。
Promise中还提供了Finally方法,无论Promise中的then、catch方法执行的结果如何,都会调用的方法,同时返回新的Promise对象,将finally中函数执行的结果传递给新Promise的value,实现链式调用。
根据Promise的功能特性,手实现简单的Promise。
// 了解Promise的3个状态 pending、fulfilled、reject
const PROMISE_STATUS_PENDING = 'PROMISE_STATUS_PENDING';
const PROMISE_STATUS_FULFILLED = 'PROMISE_STATUS_FULFILLED';
const PROMISE_STATUS_REJECT = 'PROMISE_STATUS_REJECT';
// 状态错误捕获
function executorWithErr(executor, value, resolve, reject) {
try {
const result = executor(value);
resolve(result);
} catch (error) {
reject(error)
}
}
class WtPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING;
this.value = undefined;
this.reason = undefined;
this.onFulfilledFns = [];
this.onRejectFns = [];
// Fulfilled状态执行
const resolve = (value) => {
if (this.status === PROMISE_STATUS_PENDING) {
// 添加微任务,获取回调方法
queueMicrotask(() => {
if (this.status != PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_FULFILLED;
this.value = value;
this.onFulfilledFns.forEach(fn => fn(value))
})
}
}
// Reject状态执行
const reject = (reason) => {
if (this.status === PROMISE_STATUS_PENDING) {
queueMicrotask(() => {
if (this.status != PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_REJECT;
this.reason = reason;
this.onRejectFns.forEach(fn => fn(reason))
})
}
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
// 调用then方法,返回新promise
then(onFulfilled, onReject) {
const defaultReject = err => {
throw err
};
onReject = onReject || defaultReject;
const defaultonFulfilled = value => {
return value
};
onFulfilled = onFulfilled || defaultonFulfilled;
return new WtPromise((resolve, reject) => {
if (this.status !== PROMISE_STATUS_PENDING) {
if (onFulfilled) executorWithErr(onFulfilled, this.value, resolve, resolve);
if (onReject) executorWithErr(onReject, this.reason, resolve, resolve);
}
if (this.status === PROMISE_STATUS_PENDING && onFulfilled) {
this.onFulfilledFns.push(() => {
executorWithErr(onFulfilled, this.value, resolve, reject)
})
}
if (this.status === PROMISE_STATUS_PENDING && onReject) {
this.onRejectFns.push(() => {
executorWithErr(onReject, this.reason, resolve, reject)
})
}
})
}
catch (onReject) {
return this.then(undefined, onReject)
};
finally(onfinally) {
this.then(() => {
onfinally()
}, () => {
onfinally()
})
}
static resolve(value) {
return new WtPromise(resolve => resolve(value))
}
static reject(reason) {
return new WtPromise((resolve, reject) => reject(reason))
}
static all(...promises) {
// 有reject被调用则直接调用reject方法,否则需等待所有的Resolve执行后在执行Resolve
return new WtPromise((resolve, reject) => {
const values = [];
promises.forEach(promise => {
promise.then(value => {
values.push(value);
if (values.length === promises.length) {
resolve(values)
}
}, err => {
reject(err)
})
})
})
}
static allSelter(...promises) {
return new WtPromise((resolve, reject) => {
const reslult = [];
promises.forEach(promise => {
promise.then(value => {
reslult.push({
status: PROMISE_STATUS_FULFILLED,
value: value
});
if (reslult.length === promises.length) {
resolve(reslult)
}
}, err => {
reslult.push({
status: PROMISE_STATUS_REJECT,
value: err
});
if (reslult.length === promises.length) {
resolve(reslult)
}
})
})
})
}
// 竞赛输出
static race(...promises) {
return new WtPromise((resolve, reject) => {
promises.forEach(promise => {
promise.then(res => {
resolve(res)
}, err => {
reject(err)
})
})
})
}
// 等待正确输出,否则错误集合.errors
static any(...promises) {
return new WtPromise((resolve, reject) => {
const errs = [];
promises.forEach(promise => {
promise.then(res => {
resolve(res)
}, err => {
errs.push(err);
if (errs.length === promises.length) {
reject(new AggregateError(errs))
}
})
})
})
}
}