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

掌握 JavaScript 中的承诺取消

Sep 12, 2024 am 10:32 AM

作者: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中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

前端热敏纸小票打印遇到乱码问题怎么办? 前端热敏纸小票打印遇到乱码问题怎么办? Apr 04, 2025 pm 02:42 PM

前端热敏纸小票打印的常见问题与解决方案在前端开发中,小票打印是一个常见的需求。然而,很多开发者在实...

神秘的JavaScript:它的作用以及为什么重要 神秘的JavaScript:它的作用以及为什么重要 Apr 09, 2025 am 12:07 AM

JavaScript是现代Web开发的基石,它的主要功能包括事件驱动编程、动态内容生成和异步编程。1)事件驱动编程允许网页根据用户操作动态变化。2)动态内容生成使得页面内容可以根据条件调整。3)异步编程确保用户界面不被阻塞。JavaScript广泛应用于网页交互、单页面应用和服务器端开发,极大地提升了用户体验和跨平台开发的灵活性。

谁得到更多的Python或JavaScript? 谁得到更多的Python或JavaScript? Apr 04, 2025 am 12:09 AM

Python和JavaScript开发者的薪资没有绝对的高低,具体取决于技能和行业需求。1.Python在数据科学和机器学习领域可能薪资更高。2.JavaScript在前端和全栈开发中需求大,薪资也可观。3.影响因素包括经验、地理位置、公司规模和特定技能。

JavaScript难以学习吗? JavaScript难以学习吗? Apr 03, 2025 am 12:20 AM

学习JavaScript不难,但有挑战。1)理解基础概念如变量、数据类型、函数等。2)掌握异步编程,通过事件循环实现。3)使用DOM操作和Promise处理异步请求。4)避免常见错误,使用调试技巧。5)优化性能,遵循最佳实践。

JavaScript的演变:当前的趋势和未来前景 JavaScript的演变:当前的趋势和未来前景 Apr 10, 2025 am 09:33 AM

JavaScript的最新趋势包括TypeScript的崛起、现代框架和库的流行以及WebAssembly的应用。未来前景涵盖更强大的类型系统、服务器端JavaScript的发展、人工智能和机器学习的扩展以及物联网和边缘计算的潜力。

如何使用JavaScript将具有相同ID的数组元素合并到一个对象中? 如何使用JavaScript将具有相同ID的数组元素合并到一个对象中? Apr 04, 2025 pm 05:09 PM

如何在JavaScript中将具有相同ID的数组元素合并到一个对象中?在处理数据时,我们常常会遇到需要将具有相同ID�...

如何实现视差滚动和元素动画效果,像资生堂官网那样?
或者:
怎样才能像资生堂官网一样,实现页面滚动伴随的动画效果? 如何实现视差滚动和元素动画效果,像资生堂官网那样? 或者: 怎样才能像资生堂官网一样,实现页面滚动伴随的动画效果? Apr 04, 2025 pm 05:36 PM

实现视差滚动和元素动画效果的探讨本文将探讨如何实现类似资生堂官网(https://www.shiseido.co.jp/sb/wonderland/)中�...

console.log输出结果差异:两次调用为何不同? console.log输出结果差异:两次调用为何不同? Apr 04, 2025 pm 05:12 PM

深入探讨console.log输出差异的根源本文将分析一段代码中console.log函数输出结果的差异,并解释其背后的原因。�...

See all articles