在 JavaScript 中,标准的 Promise 对象并没有提供直接中止的功能。然而,我们可以通过封装一个自定义的 CancelablePromise 来实现这一功能。以下是一个详细的代码示例和讲解,展示如何封装一个可以在外部直接中止的 Promise。
代码示例
class CancelablePromise {
constructor(executor) {
this._hasCanceled = false;
this._promise = new Promise((resolve, reject) => {
executor(
(value) => {
if (!this._hasCanceled) {
resolve(value);
}
},
(reason) => {
if (!this._hasCanceled) {
reject(reason);
}
}
);
});
}
then(onFulfilled, onRejected) {
return this._promise.then(onFulfilled, onRejected);
}
catch(onRejected) {
return this._promise.catch(onRejected);
}
finally(onFinally) {
return this._promise.finally(onFinally);
}
cancel() {
this._hasCanceled = true;
}
}
-
构造函数 (
constructor):this._hasCanceled:一个布尔值,表示Promise是否已被取消。this._promise:一个新的Promise对象,接受一个executor函数。executor函数接收两个参数:resolve和reject。我们对这两个参数进行了封装,使其在Promise被取消时不会被调用。
-
then方法:- 这个方法包装了内部的
Promise的then方法,允许外部链式调用。
- 这个方法包装了内部的
-
catch方法:- 这个方法包装了内部的
Promise的catch方法,允许外部链式调用。
- 这个方法包装了内部的
-
finally方法:- 这个方法包装了内部的
Promise的finally方法,允许外部链式调用。
- 这个方法包装了内部的
-
cancel方法:- 调用这个方法将
this._hasCanceled设置为true,表示Promise已被取消。
- 调用这个方法将
使用示例
function asyncTask() {
return new CancelablePromise((resolve, reject) => {
const timeoutId = setTimeout(() => {
resolve('Task completed');
}, 5000);
return () => clearTimeout(timeoutId);
});
}
const cancelablePromise = asyncTask();
cancelablePromise
.then((value) => {
console.log(value);
})
.catch((error) => {
console.error(error);
})
.finally(() => {
console.log('Promise settled');
});
setTimeout(() => {
cancelablePromise.cancel();
console.log('Promise canceled');
}, 2000);
讲解示例
-
定义异步任务 (
asyncTask):- 创建一个新的
CancelablePromise,在内部设置一个setTimeout模拟异步任务。 resolve在 5 秒后被调用,表示任务完成。
- 创建一个新的
-
创建可取消的
Promise(cancelablePromise):- 调用
asyncTask返回一个CancelablePromise实例。
- 调用
-
链式调用
then、catch和finally:- 使用标准的
Promise方法处理异步任务的结果。
- 使用标准的
-
取消
Promise:- 使用
setTimeout在 2 秒后调用cancelablePromise.cancel()取消Promise。 - 当
Promise被取消时,resolve和reject都不会被调用。
- 使用
通过这种方式,我们可以创建一个可取消的 Promise,并在需要时中止异步任务。这个封装在处理需要取消的异步操作时非常有用,例如网络请求或长时间运行的计算任务。