首页 > web前端 > js教程 > 掌握 JavaScript 中的承诺取消

掌握 JavaScript 中的承诺取消

WBOY
发布: 2024-09-12 10:32:30
原创
819 人浏览过

作者:Rosario De Chiara✏️

在 JavaScript 中,Promises 是处理异步操作的强大工具,在 UI 相关事件中特别有用。它们代表的值可能无法立即获得,但会在未来某个时刻得到解决。

Promise 允许(或应该允许)开发人员在处理 API 调用、用户交互或动画等任务时编写更清晰、更易于管理的代码。通过使用 .then()、.catch() 和 .finally() 等方法,Promises 能够以更直观的方式处理成功和错误场景,避免臭名昭著的“回调地狱”。

在本文中,我们将使用新的(2024 年 3 月)Promise.withResolvers() 方法,该方法允许您通过返回一个包含三件事的对象来编写更干净、更简单的代码:一个新的 Promise 和两个函数,一个用于解析 Promise另一个拒绝它,因为这是最近的更新,您将需要最新的 Node 运行时 (v>22) 来执行本文中的示例。

比较新旧 JavaScript Promise 方法

在以下两个功能等效的代码块中,我们可以比较旧方法和分配方法来解析或拒绝 Promise 的新方法:

let resolve, reject;

const promise = new Promise((res, rej) => {
  resolve = res;
  reject = rej;
});

Math.random() > 0.5 ? resolve("ok") : reject("not ok");
登录后复制

在上面的代码中,你可以看到 Promise 最传统的用法:实例化一个新的 Promise 对象,然后在构造函数中,你必须分配resolve和reject这两个函数,这两个函数将在以下情况下被调用:需要。

在下面的代码片段中,相同的代码块已使用新的 Promise.withResolvers() 方法重写,并且看起来更简单:

const { promise, resolve, reject } = Promise.withResolvers();

Math.random() > 0.5 ? resolve("ok") : reject("not ok");
登录后复制

在这里您可以看到新方法的工作原理。它返回 Promise,您可以在该 Promise 上调用 .then() 方法和两个函数:resolve 和reject。

传统的 Promise 方法将创建和事件处理逻辑封装在单个函数中,如果多个条件或代码的不同部分需要解析或拒绝 Promise,这可能会受到限制。

相比之下,Promise.withResolvers() 通过将 Promise 的创建与解析逻辑分离,提供了更大的灵活性,使其适合管理复杂的条件或多个事件。然而,对于简单的用例,传统方法对于那些习惯于标准承诺模式的人来说可能更简单、更熟悉。

真实示例:调用 API

我们现在可以在更现实的示例上测试新方法。在下面的代码中,您可以看到一个 API 调用的简单示例:

function fetchData(url) {
    return new Promise((resolve, reject) => {
        fetch(url)
            .then(response => {
                // Check if the response is okay (status 200-299)
                if (response.ok) {
                    return response.json(); // Parse JSON if response is okay
                } else {
                    // Reject the promise if the response is not okay
                    reject(new Error('API Invocation failed'));
                }
            })
            .then(data => {
                // Resolve the promise with the data
                resolve(data);
            })
            .catch(error => {
                // Catch and reject the promise if there is a network error
                reject(error);
            });
    });
}

// Example usage
const apiURL = '<ADD HERE YOU API ENDPOINT>';

fetchData(apiURL)
    .then(data => {
        // Handle the resolved data
        console.log('Data received:', data);
    })
    .catch(error => {
        // Handle any errors that occurred
        console.error('Error occurred:', error);
    });
登录后复制

fetchData 函数旨在获取 URL 并返回 Promise,该 Promise 使用 fetch API 处理 API 调用。它通过检查响应状态是否在 200-299 范围内(表示成功)来处理响应。

如果成功,响应将被解析为 JSON,并且 Promise 将使用结果数据进行解析。如果响应不成功,则 Promise 会被拒绝,并显示相应的错误消息。此外,该函数还包括错误处理以捕获任何网络错误,如果发生此类错误则拒绝 Promise。

该示例演示了如何使用此函数,展示了如何使用 .then() 块管理已解析的数据并使用 .catch() 块处理错误,确保成功的数据检索和错误得到适当的管理。

在下面的代码中,我们使用新的 Promise.withResolvers() 方法重写了 fetchData() 函数:

function fetchData(url) {
    const { promise, resolve, reject } = Promise.withResolvers();

    fetch(url)
        .then(response => {
            // Check if the response is okay (status 200-299)
            if (response.ok) {
                return response.json(); // Parse JSON if response is okay
            } else {
                // Reject the promise if the response is not okay
                reject(new Error('API Invocation failed'));
            }
        })
        .then(data => {
            // Resolve the promise with the data
            resolve(data);
        })
        .catch(error => {
            // Catch and reject the promise if there is a network error
            reject(error);
        });

    return promise;
}
登录后复制

如您所见,上面的代码更具可读性,并且 Promise 对象的作用很明确:fetchData 函数将返回一个将成功解析或将失败的 Promise,在每种情况下调用正确的方法。您可以在名为 api.inspiration.{old|new}.js.

的存储库中找到上面的代码

承诺取消

以下代码探讨了如何实现 Promise 取消方法。如您所知,您无法取消 JavaScript 中的 Promise。 Promise 代表异步操作的结果,它们被设计为一旦创建就解决或拒绝,没有内置机制来取消它们。

出现这个限制是因为 Promise 有定义的状态转换过程;它们一开始处于待定状态,一旦解决,就无法更改状态。它们旨在封装操作的结果,而不是控制操作本身,这意味着它们不能影响或取消底层过程。这种设计选择使 Promise 保持简单,并专注于表示操作的最终结果:

const cancellablePromise = () => {
    const { promise, resolve, reject } = Promise.withResolvers();

    promise.cancel = () => {
        reject("the promise got cancelled");
    };
    return promise;
};
登录后复制

In the code above, you can see the object named cancellablePromise, which is a promise with an additional cancel() method that, as you can see, simply forces the invocation of the reject method. This is just syntactic sugar and does not cancel a JavaScript Promise, though it may help in writing clearer code.

An alternative approach is to use an AbortController and AbortSignal, which can be tied to the underlying operation (e.g., an HTTP request) to cancel it when needed. From the documentation, you can see that the AbortController and AbortSignal approach is a more expressive implementation of what we implemented in the code above: once the AbortSignal is invoked, the promise just gets rejected.

Another approach is to use reactive programming libraries like RxJS, which offers an implementation of the Observable pattern, a more sophisticated control over async data streams, including cancellation capabilities.

A comparison between Observables and Promises

When speaking about practical use cases, Promises are well-suited for handling single asynchronous operations, such as fetching data from an API. In contrast, Observables are ideal for managing streams of data, such as user input, WebSocket events, or HTTP responses, where multiple values may be emitted over time.

We already clarified that once initiated, Promises cannot be canceled, whereas Observables allow for cancellation by unsubscribing from the stream. The general idea is that, with Observables, you have an explicit structure of the possible interaction with the object:

  • You create an Observable, and then all the Observables can subscribe to it
  • The Observable carries out its work, changing state and emitting events. All the Observers will receive the updates – this is the main difference with Promises. A Promise can be resolved just once while the Observables can keep emitting events as long as there are Observers
  • Once the Observer is not interested in the events from the Observables, it can unsubscribe, freeing resources

This is demonstrated in the code below:

import { Observable } from 'rxjs';

const observable = new Observable(subscriber => {
  subscriber.next(1);
  subscriber.next(2);
  subscriber.next(3);
  subscriber.complete();
});

const observer = observable.subscribe({
  next(x) { console.log('Received value:', x); },
  complete() { console.log('Observable completed'); }
});

observer.unsubscribe();
登录后复制

This code cannot be rewritten with Promises because the Observable returns three values while a Promise can only be resolved once.

To experiment further with the unsubscribe method, we can add another Observer that will use the takeWhile() method: it will let the Observer wait for values to match a specific condition; in the code below, for example, it keeps receiving events from the Observable while the value is not 2:

import { Observable, takeWhile } from 'rxjs';

const observable = new Observable(subscriber => {
  subscriber.next(1);
  subscriber.next(2);
  subscriber.next(3);
  subscriber.complete();
});

const observer1 = observable.subscribe({
  next(x) { console.log('Received by 1 value:', x); },
  complete() { console.log('Observable 1 completed'); }
});

const observer2 = observable.pipe(
  takeWhile(value => value != "2")
).subscribe(value => console.log('Received by 2 value:', value));
登录后复制

In the code above, observer1 is the same as we have already seen: it will just subscribe and keep receiving all the events from the Observable. The second one, observer2, will receive elements from the Observable while the condition is matched. In this case, this means when the value is different from 2.

From the execution, you can see how the two different mechanisms work:

$ node observable.mjs
Received by 1 value: 1
Received by 1 value: 2
Received by 1 value: 3
Observable 1 completed
Received by 2 value: 1
$
登录后复制

Conclusion

In this article, we investigated the new mechanism to allocate a Promise in JavaScript and laid out some of the possible ways to cancel a Promise before its completion. We also compared Promises with Observable objects, which not only offer the features of Promises but extend them by allowing multiple emissions of events and a proper mechanism for unsubscribing.


LogRocket: Debug JavaScript errors more easily by understanding the context

Debugging code is always a tedious task. But the more you understand your errors, the easier it is to fix them.

LogRocket allows you to understand these errors in new and unique ways. Our frontend monitoring solution tracks user engagement with your JavaScript frontends to give you the ability to see exactly what the user did that led to an error.

Mastering promise cancellation in JavaScript

LogRocket records console logs, page load times, stack traces, slow network requests/responses with headers + bodies, browser metadata, and custom logs. Understanding the impact of your JavaScript code will never be easier!

Try it for free.

以上是掌握 JavaScript 中的承诺取消的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板