译文: 理解JavaScript中的Promise以及其在React中的使用

227 阅读6分钟

Promises 是 JavaScript 中处理异步操作的基本概念。在本文中,我们将探讨在 JavaScript 中处理Promises 的各种方法以及它们在React应用程序中的常见应用。

image.png

理解 JavaScript 中的 Promises🚀

Promises 是 JavaScript 中的一个关键特性,它简化和增强了处理异步操作的能力。为了理解 Promises,让我们分解并理解下它所建立的核心组件和原则:

1. 异步操作⏳

在 JavaScript 中,许多操作需要时间才能完成,例如进行网络请求、读取/写入文件或执行耗时的任务。这些操作是异步的,意味着它们不会阻塞执行的主线程。如果没有适当的处理,它们可能会导致复杂和容易出错的代码。

2. 回调地狱😰

在 JavaScript 早期,回调是处理异步操作的主要机制。回调是在异步任务完成时执行的函数。虽然回调可以工作,但它们可能会导致所谓的“回调地狱”或“金字塔式代码结构”。当您有多个嵌套的回调时,代码就会变得难以阅读、理解和维护。

3. Promises作为解决方案🌟

Promises 被引入来解决与回调相关的问题。 Promise 是一个表示异步操作最终结果的对象。它有三种状态: 待定(pending)、已解决(resolve)和 已拒绝 (reject)。核心思想是使异步代码看起来和感觉上更像同步代码,使其更易于阅读和维护。

4. Promise状态🌈

PENDING(阻塞中): 这是 Promise 的初始状态。它表示异步操作正在进行中,结果尚不可用。
RESOLVE(已完成): 当异步操作成功时, Promise 转换为已解决状态。它包含操作的结果,例如从服务器获取的数据。
REJECT(已失败): 如果在异步操作期间发生错误,则 Promise 转换为已拒绝状态。它包含一个错误对象,提供有关失败的详细信息。

5. 链接🧩

Promise的一个强大功能是能够将多个异步操作链接在一起。这使您可以依次执行一系列任务,这通常是 JavaScript 应用程序中的常见用例。

6. .then()和.catch() 💡

Promise配备了 .then() 和 .catch() 方法。您可以将这些方法附加到Promise上,以在其解决时处理成功(resolve)或在其拒绝(reject)时捕获错误。这种方法将成功和错误处理代码清晰地分开,提高了代码组织性。

7. 错误处理🚑

Promise 通过 .catch() 方法内置错误处理,使得集中处理错误变得更加容易。这是传统基于回调的错误处理的重大改进。

创建 Promises

可以使用 Promise 构造器创建 Promise ,该构造器只需要传递一个参数,即一个包含:resolve 和 reject 参数的方法。

const myPromise = new Promise((resolve, reject) => {  
// Asynchronous code goes here  
// If the operation succeeds, call resolve with a result  
// If the operation fails, call reject with an error  
});

接下来将介绍几个 Promise 函数以及其如何工作。

Promises 方法

  • Promise.resolve(value): 这个方法返回一个已解决(resolved)的 Promise,其值为给定的值。
const resolvedPromise = Promise.resolve(42);  
resolvedPromise.then((result) => console.log(result)); // Output: 42
  • Promise.reject(reason):这个方法返回一个被拒绝(rejected)的 Promise,其原因为给定的原因。
const rejectedPromise = Promise.reject(new Error("Failed!"));  
rejectedPromise.catch((error) => console.error(error.message)); // Output: Failed!
  • Promise.all(iterable):该方法返回一个 Promise ,当可迭代对象中的所有Promise都已解决时,该 Promise 解决;当它们中的任何一个被拒绝时,该 Promise 被拒绝。
const promise1 = Promise.resolve(1);
const promise2 = Promise.resolve(2);

Promise.all([promise1, promise2]).then(values => console.log(values)); // Output: [1, 2]
  • Promise.race(iterable):该方法返回一个Promise,当可迭代对象中的任何一个Promise resolve或被reject时,该Promise为该Promise的状态。
const promise1 = new Promise((resolve) => setTimeout(resolve, 100, 'one'));  
const promise2 = new Promise((resolve) => setTimeout(resolve, 200, 'two'));  
  
Promise.race([promise1, promise2])  
.then((value) => console.log(value)); // Output: one

在 React 中使用 Promises

在 React 中,Promises 一般被用来处理异步方法,如:API 请求、管理状态变更、控制组件生命周期。

下面是一个在 React 组件中使用 Promises 的案例

import React, { useState, useEffect } from 'react';

function MyFunctionalComponent() {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    // Using a Promise to simulate an asynchronous operation
    const fetchData = () => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          // Simulate an error condition
          // reject(new Error("Failed to fetch data"));
          resolve('Data fetched!');
        }, 1000);
      });
    };

    fetchData()
      .then(result => {
        setData(result);
      })
      .catch(error => {
        setError(error.message);
      });
  }, []); // Empty dependency array to run the effect only once on mount

  return <div>{error ? <div>Error: {error}</div> : data ? <div>Data: {data}</div> : <div>Loading...</div>}</div>;
}

export default MyFunctionalComponent;

下面让我们来介绍 Promise.all 的例子。

在 React 中使用 Promise.all

除了 .then() 和 .catch() 方法之外, Promise 还提供了处理多个异步操作的强大方法。其中之一是Promise.all 方法,它允许您等待多个 Promise 达到 resolve 状态并收集它们的结果。当您需要并行从不同的源获取数据时,这特别有用。

让我们考虑一个示例,我们想要使用Promises并行获取用户的信息、他们的帖子和评论。下面是一个函数组件,演示了如何在React应用程序中使用 Promise.all

import React, { useEffect, useState } from 'react';

function UserDataComponent() {
  const [userData, setUserData] = useState(null);
  const [postData, setPostData] = useState(null);
  const [commentData, setCommentData] = useState(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    // Simulated API functions that return Promises
    function fetchUserData(userId) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          const data = { id: userId, name: `User ${userId}` };
          resolve(data);
        }, 1000);
      });
    }

    function fetchUserPosts(userId) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          const posts = [`Post 1 by User ${userId}`, `Post 2 by User ${userId}`];
          resolve(posts);
        }, 1500);
      });
    }

    function fetchUserComments(userId) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          const comments = [`Comment 1 by User ${userId}`, `Comment 2 by User ${userId}`];
          resolve(comments);
        }, 2000);
      });
    }

    const userId = 1;

    // Using Promise.all to fetch data concurrently
    Promise.all([fetchUserData(userId), fetchUserPosts(userId), fetchUserComments(userId)])
      .then(([userData, postData, commentData]) => {
        setUserData(userData);
        setPostData(postData);
        setCommentData(commentData);
      })
      .catch(error => {
        setError(error.message);
      });
  }, []);

  return (
    <div>
      {error ? (
        <div>Error: {error}</div>
      ) : (
        <div>
          {userData && <div>User Data: {userData.name}</div>}
          {postData && <div>Posts: {postData.join(', ')}</div>}
          {commentData && <div>Comments: {commentData.join(', ')}</div>}
        </div>
      )}
    </div>
  );
}

export default UserDataComponent;

在这个案例中,我们并行的获取了用户的信息、帖子和评论,当请求成功后,我们使用获取到的数据更新组件,该方法能够有效的帮助提高多个异步任务请求的执行效率。

接下来介绍 Promise.race 的例子。

在 React 中使用Promise.race

除了 Promise.all 之外,Promises 还提供了一个叫做 Promise.race 的方法, 当你想要获取第一个返回的请求结果时,可以使用 Promise.race 。当你执行多个异步方法,该方法帮助你获取返回结果最快的那个Promise结果。

下面是一个Promise.race的例子

import React, { useEffect, useState } from 'react';

function FastestDataComponent() {
  const [fastestData, setFastestData] = useState(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    // Simulated API functions that return Promises
    function fetchFastData() {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve('Fast data fetched!');
        }, 500); // Resolves in 500 milliseconds
      });
    }

    function fetchSlowData() {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve('Slow data fetched!');
        }, 1500); // Resolves in 1500 milliseconds
    }

    // Using Promise.race to get the result of the fastest request
    Promise.race([fetchFastData(), fetchSlowData()])
      .then((result) => {
        setFastestData(result);
      })
      .catch((error) => {
        setError(error.message);
      });
  }, []);

  return (
    <div>
      {error ? (
        <div>Error: {error}</div>
      ) : fastestData ? (
        <div>Fastest Data: {fastestData}</div>
      ) : (
        <div>Loading...</div>
      )}
    </div>
  );
}

export default FastestDataComponent;

在这个示例中,我们使用 Promise.race 从两个源获取数据。第一个源( fetchFastData )在500毫秒内解决,而第二个源( fetchSlowData )在1500毫秒内解决。该组件显示最快请求的结果。当您想从最快的可用源提供结果来提供更快的用户体验时,这个方法特别有用。

结论

Promises 是 JavaScript 和 React 中管理异步操作的关键部分。无论您是处理简单的数据获取,使用Promise.all并行处理多个异步任务,还是使用Promise.race从最快的源获取结果,Promises 提供了一种有组织和结构化的方式来处理异步代码。了解这些不同的 Promise 方法以及如何在 React 中使用它们可以显著增强您构建强大的响应式应用程序的能力。

原文链接

如侵则删