enum State {
PENDING = "pending",
RESOLVED = "resolved",
REJECTED = "rejected",
}
type Resolve<T> = (value?: T) => void;
type Reject = (reason: any) => void;
type Executor<T> = (resolve: Resolve<T>, reject: Reject) => void;
class TypePromise<T = unknown> {
private state: State = State.PENDING;
private value?: T;
private reason: any;
constructor(executor: Executor<T>) {
executor(this.resolve.bind(this), this.reject.bind(this));
}
private resolve(value?: T) {
if (this.state === State.PENDING) {
this.state = State.FULFILLED;
this.value = value;
}
}
private reject(reason: any) {
if (this.state === State.PENDING) {
this.state = State.REJECTED;
this.reason = reason;
}
}
}
Promise
中最重要的一环就是.then
方法的实现,这里我们先做一个简单的版本
class TypePromise<T = unknown> {
...
public then<V = unknown>(
onFulfilled: (value: T) => V,
onRejected: (reason: any) => any,
) {
if (this.state === State.FULFILLED) {
onFulfilled(this.value as T);
} else if (this.state === State.REJECTED) {
onRejected(this.reason as any);
}
}
}
这里生成一个随机数来测试调用resolve
还是reject
, 当调用了resolve
后它应该不执行reject
new TypePromise((resolve, reject) => {
const i = Math.random() * 10;
console.log({ i });
if (i < 5) {
resolve("success");
}
reject("failed");
}).then(
(res) => {
console.log(res);
},
(err) => {
console.log(err);
},
);
首先添加回调的队列
class TypePromise<T = unknown> {
...
private onFulfilledCallbacks: Resolve<T>[] = [];
private onRejectedCallbacks: Reject[] = [];
...
}
由于是异步函数,在构造函数做个try catch
以防意外。
class TypePromise<T = unknown> {
...
constructor(executor: Executor<T>) {
try {
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (e) {
this.reject(e);
}
}
...
}
对reason
和reject
方法做队列的执行处理,这里我们使用QueueMicrotask
class TypePromise<T = unknown> {
...
private resolve(value?: T) {
if (this.state === State.PENDING) {
this.state = State.FULFILLED;
this.value = value;
this.onFulfilledCallbacks.forEach((task) => {
queueMicrotask(() => task(this.value));
});
}
}
private reject(reason: any) {
if (this.state === State.PENDING) {
this.state = State.REJECTED;
this.reason = reason;
this.onRejectedCallbacks.forEach((task) => {
queueMicrotask(() => task(this.reason));
});
}
}
...
}
还需要在then
上做一些工作,使其也支持队列模式
class TypePromise<T = unknown> {
...
public then<V = unknown>(
onFulfilled?: (value?: T) => V,
onRejected?: (reason: any) => any,
) {
return new TypePromise<V>((resolve, reject) => {
const handleFulfilled = (value?: T) => {
try {
const result = onFulfilled ? onFulfilled(value) : value;
resolve(result as V);
} catch (e) {
reject(e);
}
};
const handleRejected = (reason: any) => {
try {
const result = onRejected ? onRejected(reason) : reason;
reject(result);
} catch (e) {
reject(e);
}
};
if (this.state === State.FULFILLED) {
queueMicrotask(() => handleFulfilled(this.value));
} else if (this.state === State.REJECTED) {
queueMicrotask(() => handleRejected(this.reason));
} else {
this.onFulfilledCallbacks.push(handleFulfilled);
this.onRejectedCallbacks.push(handleRejected);
}
});
}
}
此时我们可以使用最经典的异步方法来测试下
new TypePromise((resolve) => {
setTimeout(() => {
resolve("success frist");
});
})
.then((res) => {
console.log(res);
return "success second";
})
.then((res) => {
console.log(res);
});
enum State {
PENDING = "pending",
FULFILLED = "fulfilled",
REJECTED = "rejected",
}
type Resolve<T> = (value?: T) => void;
type Reject = (reason: any) => void;
type Executor<T> = (resolve: Resolve<T>, reject: Reject) => void;
class TypePromise<T = unknown> {
private state: State = State.PENDING;
private value?: T;
private reason: any;
private onFulfilledCallbacks: Resolve<T>[] = [];
private onRejectedCallbacks: Reject[] = [];
constructor(executor: Executor<T>) {
try {
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (e) {
this.reject(e);
}
}
private resolve(value?: T) {
if (this.state === State.PENDING) {
this.state = State.FULFILLED;
this.value = value;
this.onFulfilledCallbacks.forEach((task) => {
queueMicrotask(() => task(this.value));
});
}
}
private reject(reason: any) {
if (this.state === State.PENDING) {
this.state = State.REJECTED;
this.reason = reason;
this.onRejectedCallbacks.forEach((task) => {
queueMicrotask(() => task(this.reason));
});
}
}
public then<V = unknown>(
onFulfilled?: (value?: T) => V,
onRejected?: (reason: any) => any,
) {
return new TypePromise<V>((resolve, reject) => {
const handleFulfilled = (value?: T) => {
try {
const result = onFulfilled ? onFulfilled(value) : value;
resolve(result as V);
} catch (e) {
reject(e);
}
};
const handleRejected = (reason: any) => {
try {
const result = onRejected ? onRejected(reason) : reason;
reject(result);
} catch (e) {
reject(e);
}
};
if (this.state === State.FULFILLED) {
queueMicrotask(() => handleFulfilled(this.value));
} else if (this.state === State.REJECTED) {
queueMicrotask(() => handleRejected(this.reason));
} else {
this.onFulfilledCallbacks.push(handleFulfilled);
this.onRejectedCallbacks.push(handleRejected);
}
});
}
}
new TypePromise((resolve, reject) => {
const i = Math.random() * 10;
console.log({ i });
if (i < 5) {
resolve("success");
}
reject("failed");
}).then(
(res) => {
console.log(res);
},
(err) => {
console.log(err);
},
);
new TypePromise((resolve) => {
setTimeout(() => {
resolve("success frist");
});
})
.then((res) => {
console.log(res);
return "success second";
})
.then((res) => {
console.log(res);
});