在 JavaScript 中,Promise 是一个非常常用的异步编程模式。但是在实际使用过程中,我们经常会遇到一个问题:如何取消一个 Promise?
在许多情况下,我们可能需要在 Promise 还没有完成之前取消它。比如用户在操作过程中取消了一个请求,或者在页面切换时需要取消正在进行的一些异步操作等等。
本文将介绍如何解决 JavaScript 中 Promise 的 Cancelled 问题,并提供一些示例代码供大家参考。
Promise 的基本用法
在开始讲解如何取消 Promise 之前,我们先来回顾一下 Promise 的基本用法。
Promise 是一个异步操作的容器,它可以将异步操作封装成一个对象,使得我们能够更方便地进行异步编程。一个 Promise 对象有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。
我们可以通过 Promise 的 then 方法来注册成功回调函数,通过 catch 方法来注册失败回调函数。当 Promise 的状态发生变化时,对应的回调函数就会被调用。
下面是一个简单的示例代码:
-- -------------------- ---- ------- -------- ---------- - ------ --- ----------------- ------- -- - ----- --- - --- ----------------- --------------- ----- ---------- - -- -- - -- ----------- --- ---- - ---------------------- - ---- - ---------- ----------------------- - -- ----------- - -- -- - ---------- -------------- --------- -- ----------- --- - ----------------------------------------------------- -------------- -- - ---------------------- -- ------------ -- - --------------------- ---
在这个示例中,我们定义了一个 fetch 函数,它返回一个 Promise 对象。在 Promise 对象的构造函数中,我们使用 XMLHttpRequest 发送了一个 GET 请求,并在请求完成后根据响应状态来决定 Promise 的状态。如果请求成功,我们调用 resolve 方法将 Promise 的状态设置为 fulfilled,并将响应数据作为参数传递给成功回调函数;如果请求失败,我们调用 reject 方法将 Promise 的状态设置为 rejected,并将错误信息作为参数传递给失败回调函数。
在使用 fetch 函数时,我们可以通过 then 方法来注册成功回调函数,通过 catch 方法来注册失败回调函数。当 Promise 对象的状态发生变化时,对应的回调函数就会被调用。
如何取消 Promise
在实际使用 Promise 的过程中,我们可能需要在 Promise 还没有完成之前取消它。比如在用户操作过程中取消一个请求,或者在页面切换时需要取消正在进行的一些异步操作等等。
那么,如何取消 Promise 呢?
在 JavaScript 中,Promise 并没有提供一个标准的取消方法。但是我们可以通过一些技巧来实现 Promise 的取消。
方法一:使用 AbortController
AbortController 是一个新的 Web API,它可以用来取消 Fetch 请求、Web Socket 连接等等。我们可以利用 AbortController 来实现 Promise 的取消。
首先,我们需要在 Promise 的构造函数中传入一个 AbortController 对象,并将其保存在 Promise 实例中。然后,在需要取消 Promise 的时候,我们可以调用 AbortController 的 abort 方法来取消 Promise。
下面是一个使用 AbortController 实现 Promise 取消的示例代码:
-- -------------------- ---- ------- -------- ---------- - ----- ---------- - --- ------------------ ----- ------ - ------------------ ----- ------- - --- ----------------- ------- -- - ----- --- - --- ----------------- --------------- ----- ---------- - -- -- - -- ----------- --- ---- - ---------------------- - ---- - ---------- ----------------------- - -- ----------- - -- -- - ---------- -------------- --------- -- ----------- -------------------------------- -- -- - ------------ ---------- -------------------- --- --- ------------------ - ----------- ------ -------- - ----- ------- - ------------------------------------------------------ ------- -------------- -- - ---------------------- -- ------------ -- - --------------------- --- ------------- -- - --------------------------- -- ------
在这个示例中,我们在 Promise 的构造函数中创建了一个 AbortController 对象,并将其保存在 Promise 实例中。然后,在发送请求时,我们将 AbortController 的 signal 属性作为 XMLHttpRequest 的 abort 方法的参数,这样当 AbortController 调用 abort 方法时,XMLHttpRequest 也会被取消。
同时,我们还通过 signal 的 addEventListener 方法注册了一个 abort 事件的回调函数,在 Promise 被取消时会调用该回调函数,并在回调函数中调用 reject 方法将 Promise 的状态设置为 rejected。
最后,我们在 setTimeout 中调用了 promise.controller.abort 方法来取消 Promise。
方法二:使用 race 方法
另一种实现 Promise 取消的方法是使用 Promise 的 race 方法。
Promise 的 race 方法可以接受一个 Promise 数组作为参数,并返回一个新的 Promise 对象。当 Promise 数组中的任意一个 Promise 对象的状态发生变化时,返回的 Promise 对象就会跟着变化。
我们可以利用这个特性来实现 Promise 的取消。具体来说,我们可以将一个 Promise 对象和一个 Promise.race([Promise.resolve(), cancelPromise]) 的结果一起放在 Promise.all([promise, Promise.race([Promise.resolve(), cancelPromise])]) 中,这样当 cancelPromise 被 resolve 时,Promise.all 返回的 Promise 对象就会被取消。
下面是一个使用 race 方法实现 Promise 取消的示例代码:
-- -------------------- ---- ------- -------- ---------- - ----- ------- - --- ----------------- ------- -- - ----- --- - --- ----------------- --------------- ----- ---------- - -- -- - -- ----------- --- ---- - ---------------------- - ---- - ---------- ----------------------- - -- ----------- - -- -- - ---------- -------------- --------- -- ----------- --- ----- ------------- - --- ----------------- ------- -- - ------------- -- - ---------- -------------------- -- ------ --- ------ --------------------- -------------------------------- ----------------- ------------------ -- --------- ------------ -- - --------------------- ----- ------ --- - ----- ------- - ------------------------------------------------------ ------- -------------- -- - ---------------------- -- ------------ -- - --------------------- --- ------------- -- - ---------------- -- ---- -- -----
在这个示例中,我们首先定义了一个 cancelPromise,它会在 1 秒后被 reject。然后,在 fetch 函数中,我们将 promise 和 Promise.race([Promise.resolve(), cancelPromise]) 的结果一起放在 Promise.all([promise, Promise.race([Promise.resolve(), cancelPromise])]) 中,这样当 cancelPromise 被 reject 时,Promise.all 返回的 Promise 对象就会被取消。
最后,我们在 setTimeout 中调用了 promise.catch(() => {}),这样就可以忽略掉 Promise 的取消异常,避免在控制台中出现错误信息。
总结
在 JavaScript 中,Promise 是一个非常常用的异步编程模式。但是在实际使用过程中,我们经常会遇到一个问题:如何取消一个 Promise?
在本文中,我们介绍了两种实现 Promise 取消的方法:使用 AbortController 和使用 race 方法。这些方法虽然不是标准的 Promise API,但是它们可以让我们更方便地进行异步编程,提升代码的可读性和可维护性。
在使用这些方法时,我们需要注意一些细节,比如避免在控制台中出现取消异常等等。但是只要我们掌握了这些技巧,就可以更加自如地使用 Promise,写出更加优雅和高效的异步代码。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/65bc8533add4f0e0ff524100