promise 解决了什么问题
promise 主要是为了解决异步编程中,回调函数嵌套过多代码难以维护的问题,主要采用链式调用的方式进行解决。解决了异步发生异常时统一的异步异常处理的问题。另外ES6还通过扩展方法,all allsettled 以及 race解决了并发编程的问题,基于这几个方法,可以更简单的实现asynPool这种方法,对页面的过多请求进行控制
promise基本概念
- promise有三个状态,pending fulfilled rejected,其中pending只可以变为fulfilled 或者 rejected,且状态不可逆
- 每个promise对象都有一个then方法,接受两个函数,onFulfilled 和 onRejected,一个是成功时执行,一个是失败时执行
- Promise的构造函数接受一个exectur函数,这个函数是同步执行的,这个函数接受两个参数,resolve和reject,负责更改promise的状态,resolve传入的值为value,会传递至onFulfilled中执行,reject传入的值为reason,会传入onRejected执行,另外,如果exectur函数执行过程中报错,也会传递至onRejected执行
- promise的then方法如果返回一个promise,会将返回的promise的结果传递至then的onFulfilled和onRejected中,走哪个函数取决于返回的promise是成功还是失败
- promise的onRejected如果捕获了异常,且onRejected中没有报错,没有返回失败状态的Promise,则会走到下一个then的onFulfilled中
promise的实现
Promise的实现基本上可以按照三步走,分别是同步版本的实现,异步版本的实现,以及当返回值是promise时如何处理,那我们就一步一步来吧
- 同步版本的实现
const state = { // Promise的基本状态
pending: "PENDING",
fulfilled: "FULFILLED",
rejected: "REJECTED",
};
class Promise {
state = state.pending;
value = undefined;
reason = undefined;
constructor(exectur) {
const resolve = (value) => {
if (this.state === state.pending) {
this.value = value;
this.state = state.fulfilled;
}
};
const reject = (reason) => {
if (this.state === state.pending) {
this.reason = reason;
this.state = state.rejected;
}
};
exectur(resolve, reject);
}
then(onFufilled, onRejected) {
if (this.state === state.fulfilled) {
onFufilled(this.value);
}
if (this.state === state.rejected) {
onRejected(this.reason);
}
}
}
export default Promise;
- 异步版本的实现,异步的实现主要是借助了发布订阅,在resolve时将then方法储存的成功或者失败函数批量执行
const state = {
pending: "PENDING",
fulfilled: "FULFILLED",
rejected: "REJECTED",
};
class Promise {
state = state.pending;
value = undefined;
reason = undefined;
fulfilledCallbacks = [];
rejectedCallbacks = [];
constructor(exectur) {
const resolve = (value) => {
if (this.state === state.pending) {
this.value = value;
this.state = state.fulfilled;
this.fulfilledCallbacks.forEach((fn) => fn());
}
};
const reject = (reason) => {
if (this.state === state.pending) {
this.reason = reason;
this.state = state.rejected;
this.rejectedCallbacks.forEach((fn) => fn());
}
};
exectur(resolve, reject);
}
then(onFufilled, onRejected) {
const promise = new Promise((resolve, reject) => {
if (this.state === state.fulfilled) {
const x = onFufilled(this.value);
}
if (this.state === state.rejected) {
const x = onRejected(this.reason);
}
if (this.state === state.pending) {
this.fulfilledCallbacks.push(() => {
const x = onFufilled(this.value);
});
this.rejectedCallbacks.push(() => {
const x = onRejected(this.reason);
});
}
});
return promise;
}
}
export default Promise;
- then中返回Promise时如何处理
const state = {
pending: "PENDING",
fulfilled: "FULFILLED",
rejected: "REJECTED",
};
class Promise {
state = state.pending;
value = undefined;
reason = undefined;
fulfilledCallbacks = [];
rejectedCallbacks = [];
constructor(exectur) {
const resolve = (value) => {
if (this.state === state.pending) {
this.value = value;
this.state = state.fulfilled;
this.fulfilledCallbacks.forEach((fn) => fn());
}
};
const reject = (reason) => {
if (this.state === state.pending) {
this.reason = reason;
this.state = state.rejected;
this.rejectedCallbacks.forEach((fn) => fn());
}
};
exectur(resolve, reject);
}
then(onFufilled, onRejected) {
const promise = new Promise((resolve, reject) => {
if (this.state === state.fulfilled) {
process.nextTick(() => {
const x = onFufilled(this.value);
resolvePromise(promise, x, resolve, reject);
});
}
if (this.state === state.rejected) {
process.nextTick(() => {
const x = onRejected(this.reason);
resolvePromise(promise, x, resolve, reject);
});
}
if (this.state === state.pending) {
this.fulfilledCallbacks.push(() => {
process.nextTick(() => {
const x = onFufilled(this.value);
resolvePromise(promise, x, resolve, reject);
});
});
this.rejectedCallbacks.push(() => {
process.nextTick(() => {
const x = onRejected(this.reason);
resolvePromise(promise, x, resolve, reject);
});
});
}
});
return promise;
}
}
function resolvePromise(promise, x, resolve, reject) {
if (promise === x) {
throw new TypeError("123");
}
if ((typeof x === "object" && x != null) || typeof x === "function") {
const then = x.then;
if (typeof then === "function") {
then.call(
x,
(y) => {
resolve(y);
},
(r) => {
reject(r);
}
);
}
}
resolve(x);
}
export default Promise;