【react】在react中async/await一般用来实现什么功能

目录

基本概念

工作原理

优点

注意事项

底层原理

实际应用场景

1. 数据获取 (API 请求)

2. 表单提交

3. 异步状态管理

4. 异步路由切换

5. 异步数据预加载

6. 第三方 API 调用

7. 文件上传/下载

8. 路由导航拦截

关键注意事项


基本概念

async 函数:用 async 关键字声明的函数会返回一个 Promise。如果函数中返回的不是 Promise,JavaScript 会将其包装成一个 resolved 的 Promise

await 关键字:只能用在 async 函数内部,用于等待一个 Promise 的解决结果。如果等待的不是 Promiseawait 会直接返回该值。

示例代码

// 定义一个异步函数
async function fetchData() {try {// 模拟一个异步操作,比如网络请求const response = await fetch('https://api.example.com/data');const data = await response.json(); // 解析响应体为 JSONconsole.log(data);} catch (error) {console.error('Error fetching data:', error);}
}// 调用异步函数
fetchData();

工作原理

async 函数返回一个 Promise

如果函数中返回的是一个普通值,这个值会被包装成一个 resolved 的 Promise

如果函数中返回的是一个 Promise,则直接返回该 Promise

await 暂停函数执行

当遇到 await 时,函数的执行会被暂停,直到等待的 Promise 被解决。

如果等待的不是一个 Promiseawait 会直接返回该值,并继续执行后续代码。

优点

更简洁的代码:相比传统的 Promise 链式调用,async/await 让异步代码看起来像同步代码,逻辑更清晰。

易于调试:错误堆栈更清晰,调试时更容易追踪代码的执行流程。

避免回调地狱:通过 await 逐层等待,避免了嵌套回调的复杂性。

注意事项

只能在 async 函数中使用 await

// 错误:await 不能在普通函数中使用
function normalFunction() {const result = await somePromise(); // 语法错误
}

错误处理

async function fetchData() {try {const response = await fetch('https://api.example.com/data');const data = await response.json();console.log(data);} catch (error) {console.error('Error:', error);}
}

使用 try/catch 块捕获 await 的错误,而不是 .catch()

并发执行: 如果有多个异步操作需要同时执行,可以使用 Promise.all()

async function fetchMultipleData() {const [data1, data2] = await Promise.all([fetch('https://api.example.com/data1').then(res => res.json()),fetch('https://api.example.com/data2').then(res => res.json())]);console.log(data1, data2);
}

底层原理

async/await 的底层是基于 Promise 和事件循环的。当执行一个 async 函数时,函数内部的代码会被包装成一个 Promise,并立即执行。遇到 await 时,当前函数的执行会被暂停,直到等待的 Promise 被解决。解决后,函数会从暂停的地方继续执行。

实际应用场景

1. 数据获取 (API 请求)

从服务器获取数据是最常见的异步操作场景。

import React, { useState, useEffect } from 'react';const DataFetcher = () => {const [data, setData] = useState(null);const [loading, setLoading] = useState(true);const [error, setError] = useState(null);useEffect(() => {const fetchData = async () => {try {const response = await fetch('https://api.example.com/data');if (!response.ok) {throw new Error('Network response was not ok');}const jsonData = await response.json();setData(jsonData);} catch (error) {setError(error.message);} finally {setLoading(false);}};fetchData();}, []);if (loading) return <div>Loading...</div>;if (error) return <div>Error: {error}</div>;return <div>{JSON.stringify(data)}</div>;
};export default DataFetcher;

2. 表单提交

处理表单提交时,使用 async/await 等待服务器响应。

import React, { useState } from 'react';const AsyncForm = () => {const [name, setName] = useState('');const [email, setEmail] = useState('');const [status, setStatus] = useState('idle');const handleSubmit = async (e) => {e.preventDefault();setStatus('submitting');try {const response = await fetch('https://api.example.com/submit', {method: 'POST',headers: {'Content-Type': 'application/json',},body: JSON.stringify({ name, email }),});if (!response.ok) {throw new Error('Failed to submit');}setStatus('success');} catch (error) {setStatus(`Error: ${error.message}`);}};return (<form onSubmit={handleSubmit}><inputtype="text"value={name}onChange={(e) => setName(e.target.value)}placeholder="Name"/><inputtype="email"value={email}onChange={(e) => setEmail(e.target.value)}placeholder="Email"/><button type="submit" disabled={status === 'submitting'}>{status === 'submitting' ? 'Submitting...' : 'Submit'}</button>{status === 'success' && <div>Submitted successfully!</div>}{status.startsWith('Error') && <div>{status}</div>}</form>);
};export default AsyncForm;

3. 异步状态管理

在组件中管理异步状态。

import React, { useState } from 'react';const AsyncStateExample = () => {const [data, setData] = useState(null);const [loading, setLoading] = useState(true);const fetchData = async () => {try {const response = await fetch('https://api.example.com/data');if (!response.ok) {throw new Error('Network response was not ok');}const jsonData = await response.json();setData(jsonData);} catch (error) {console.error('Error fetching data:', error);} finally {setLoading(false);}};return (<div><button onClick={fetchData} disabled={loading}>{loading ? 'Loading...' : 'Fetch Data'}</button>{data && <div>{JSON.stringify(data)}</div>}</div>);
};export default AsyncStateExample;

4. 异步路由切换

在使用 React Router 时,完成异步操作后再切换路由。

import React, { useState } from 'react';
import { useHistory } from 'react-router-dom';const AsyncRouteExample = () => {const [username, setUsername] = useState('');const history = useHistory();const handleLogin = async () => {try {await new Promise((resolve) => setTimeout(resolve, 1000));history.push('/dashboard');} catch (error) {console.error('Login failed:', error);}};return (<div><inputtype="text"value={username}onChange={(e) => setUsername(e.target.value)}placeholder="Username"/><button onClick={handleLogin}>Login</button></div>);
};export default AsyncRouteExample;

5. 异步数据预加载

在组件渲染前预加载数据。

import React, { useState, useEffect } from 'react';const AsyncDataPreload = () => {const [data, setData] = useState(null);const [loading, setLoading] = useState(true);useEffect(() => {const preloadData = async () => {try {const response = await fetch('https://api.example.com/data');if (!response.ok) {throw new Error('Network response was not ok');}const jsonData = await response.json();setData(jsonData);} catch (error) {console.error('Error preloading data:', error);} finally {setLoading(false);}};preloadData();}, []);if (loading) return <div>Loading data...</div>;return <div>{JSON.stringify(data)}</div>;
};export default AsyncDataPreload;

6. 第三方 API 调用

与浏览器 API 或第三方 SDK 交互。

async function getGeolocation() {return new Promise((resolve, reject) => {navigator.geolocation.getCurrentPosition(resolve, reject);});
}function LocationButton() {const [position, setPosition] = useState(null);const handleClick = async () => {try {const pos = await getGeolocation();setPosition({lat: pos.coords.latitude,lng: pos.coords.longitude});} catch (err) {alert('无法获取位置信息');}};return (<div><button onClick={handleClick}>获取当前位置</button>{position && <Map coordinates={position} />}</div>);
}

7. 文件上传/下载

处理文件上传并跟踪进度。

import axios from 'axios';function FileUploader() {const [progress, setProgress] = useState(0);const uploadFile = async (file) => {const formData = new FormData();formData.append('file', file);await axios.post('/api/upload', formData, {onUploadProgress: (e) => {setProgress(Math.round((e.loaded * 100) / e.total));}});};return (<div><input type="file" onChange={e => uploadFile(e.target.files[0])} />{progress > 0 && <ProgressBar value={progress} />}</div>);
}

8. 路由导航拦截

防止用户在有未保存更改时离开页面。

import { useNavigate, useLocation } from 'react-router-dom';function EditArticle() {const [isDirty, setIsDirty] = useState(false);const navigate = useNavigate();useEffect(() => {const unblock = navigate.block((tx) => {if (isDirty && !window.confirm('有未保存的更改,确定离开?')) {tx.retry();}});return () => unblock();}, [isDirty]);const saveArticle = async () => {await fetch('/api/articles', { method: 'PUT' });setIsDirty(false);navigate('/articles');};return (/* 编辑器 UI */);
}

关键注意事项

  1. 组件卸载时的处理useEffect 中使用标志位避免组件卸载后的状态更新。

useEffect(() => {let isMounted = true;const fetchData = async () => {const data = await fetch('/api/data');if (isMounted) setData(data);};fetchData();return () => { isMounted = false; };
}, []);
  1. 错误处理 捕获并处理异步操作中的错误,避免未处理的承诺拒绝。

try {await fetchData();
} catch (error) {if (error.name !== 'AbortError') {showErrorToast(error.message);}
}
  1. 防抖优化 对频繁触发的异步操作使用防抖。

const search = useDebouncedCallback(async (query) => {const results = await fetchResults(query);setResults(results);
}, 500);

通过以上示例和注意事项,可以全面了解在 React 中如何使用 async/await 处理各种异步场景,提升应用的响应性和用户体验。

React 中 async/await 的典型应用场景包括:

  1. 网络请求(GET/POST/PUT/DELETE)

  2. 文件操作(上传/下载)

  3. 浏览器 API 调用(地理位置/摄像头)

  4. 定时任务(延迟执行)

  5. WebSocket 通信

  6. 数据库操作(IndexedDB)

  7. 动画序列控制

  8. 第三方库集成(支付 SDK)

合理使用异步操作可以使:

  • 代码逻辑更清晰(避免回调地狱)

  • 错误处理更直观(try/catch 统一捕获)

  • 用户体验更友好(加载状态/进度提示)

码字不易,各位大佬点点赞呗

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/41665.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QT记事本

记事本应用程序提供了基本的文本编辑功能&#xff0c;支持文件的新建、打开、保存和另存为操作&#xff0c;同时具备修改提示和关闭窗口时的保存确认功能。使用 UTF - 8 编码确保了对多语言文本的支持。 1. 项目整体结构 main.cpp&#xff1a;程序的入口点&#xff0c;负责初…

如何用 Postman 发送 POST 请求?

POST 请求是 HTTP 协议中用于提交数据的一种方法&#xff0c;Postman 提供了丰富的功能来支持用户发送包含各种信息的 POST 请求&#xff0c;如文本数据、JSON 或 XML 数据结构、文件等。 Postman 发送 post 请求教程

Ant Design Vue 中的table表格高度塌陷,造成行与行不齐的问题

前言&#xff1a; Ant Design Vue: 1.7.2 Vue2 less 问题描述&#xff1a; 在通过下拉框选择之后&#xff0c;在获取接口数据&#xff0c;第一列使用了fixed:left&#xff0c;就碰到了高度塌陷&#xff0c;查看元素的样式结果高度不一致&#xff0c;如&#x…

Flink 通过 Chunjun Oracle LogMiner 实时读取 Oracle 变更日志并写入 Doris 的方案

文章目录 一、 技术背景二、 关键技术1、 Oracle LogMiner2、 Chunjun 的 LogMiner 关键流程3、修复 Chunjun Oracle LogMiner 问题 一、 技术背景 在大数据实时同步场景中&#xff0c;需要将 Oracle 数据库的变更数据&#xff08;CDC&#xff09; 采集并写入 Apache Doris&am…

qt+opengl 加载三维obj文件

1前面我们已经熟悉了opengl自定义顶点生成一个立方体&#xff0c;并且我们实现了立方体的旋转&#xff0c;光照等功能。下面我们来用opengl来加载一个obj文件。准备我们首先准备一个简单的obj文件&#xff08;head.obj&#xff09;。资源在本页下载 2 在obj文件里面&#xff0c…

计算机组成原理的学习day01

一 计算机系统层次结构 1 计算机硬件的基本组成 好的&#xff0c;上个小节中我们了解了计算机系统的概念&#xff0c;还有计算机的一个发展历程&#xff0c;那这个小节中我们会着重的探讨计算机硬件的一个基本组成。我们需要掌握这样的两种结构&#xff0c;第一种是早期的冯诺…

ASP 应用HTTP.SYS短文件文件解析Access 注入数据库泄漏

#ASP- 默认安装 -MDB 数据库泄漏下载&#xff08;路径是知道的话可以直接下载&#xff09; 由于大部分 ASP 程序与 ACCESS 数据库搭建&#xff0c;但 ACCESS 无需连接&#xff0c;都在脚本文件中定 义配置好数据库路径即用&#xff0c;不需要额外配置安装数据库&#x…

Redis 版本演进及主要新特性

Redis 版本发布历史 稳定版本时间线 Redis 2.6 (2012年)Redis 2.8 (2013年11月)Redis 3.0 (2015年4月) - 首次支持集群Redis 3.2 (2016年5月)Redis 4.0 (2017年7月)Redis 5.0 (2018年10月)Redis 6.0 (2020年4月)Redis 6.2 (2021年2月)Redis 7.0 (2022年4月) - 最新稳定版(截至…

从 MySQL 到时序数据库 TDengine:Zendure 如何实现高效储能数据管理?

小T导读&#xff1a;TDengine 助力广州疆海科技有限公司高效完成储能业务的数据分析任务&#xff0c;轻松应对海量功率、电能及输入输出数据的实时统计与分析&#xff0c;并以接近 1 : 20 的数据文件压缩率大幅降低存储成本。此外&#xff0c;taosX 强大的 transform 功能帮助用…

NVM安装速通使用手册(Windows版)NVM管理node版本命令手册 NVM使用手册

nvm&#xff08;Node Version Manager&#xff09;是一个用于管理Node.js版本的命令行工具。通过nvm&#xff0c;你可以在同一台机器上安装和切换多个Node.js版本&#xff0c;非常适合开发和测试在不同Node.js版本上运行的应用程序 一、安装地址 1. 官方下载&#xff1a; &…

qt QQuaternion详解

1. 概述 QQuaternion 是 Qt 中用于表示三维空间中旋转的四元数类。它包含一个标量部分和一个三维向量部分&#xff0c;可以用来表示旋转操作。四元数在计算机图形学中广泛用于平滑的旋转和插值。 2. 重要方法 默认构造函数 QQuaternion::QQuaternion(); // 构造单位四元数 (1…

Axure项目实战:智慧城市APP(四)医疗信息(动态面板、选中交互应用)

亲爱的小伙伴&#xff0c;在您浏览之前&#xff0c;烦请关注一下&#xff0c;在此深表感谢&#xff01; 课程主题&#xff1a;智慧城市APP医疗信息模块 主要内容&#xff1a;医疗信息模块原型设计与交互 应用场景&#xff1a;医疗信息行业 案例展示&#xff1a; 案例视频&…

DeepSeek助力文案,智能音箱如何改变你的生活?

你好&#xff0c;我是三桥君 你有没有为写智能音箱的宣传文案而抓耳挠腮过&#xff1f;三桥君在这方面可是有些感想&#xff0c;今天就来给你唠唠怎么用DeepSeek写出超赞的智能音箱宣传文案。 首先&#xff0c;你得给DeepSeek喂足“料”。这就好比做饭&#xff0c;你得准备好各…

二叉树的前,中,后序遍历

我们来了解一下二叉树的遍历&#xff0c;话不多说 二叉树的遍历的概念&#xff1a; 二叉树有四种遍历方式&#xff0c;分别为前序遍历&#xff0c;中序遍历&#xff0c;后序遍历和层序遍历&#xff0c;但我们今天谈谈前三种&#xff0c;并实现它 前序遍历&#xff1a; 按照根…

Linux网站搭建(新手必看)

1.宝塔Linux面板的功能 宝塔面板是一款服务器管理软件&#xff0c;可以帮助用户建立网站&#xff0c;一键配置服务器环境&#xff0c;使得用户通过web界面就可以轻松的管理安装所用的服务器软件。 2. 宝塔Linux面板的安装 宝塔官网地址&#xff1a;宝塔面板 - 简单好用的Linu…

secp256k1的模数P是如何选择的?

在区块链和现代密码学中&#xff0c;secp256k1 椭圆曲线以其高安全性和高效运算性能而著称。你可能注意到&#xff0c;secp256k1 的曲线方程为 而其中的模数 p 被定义为 那么&#xff0c;为何会选择这样一个看似复杂的数呢&#xff1f;本文将从多个角度为你详细解析这一选择背后…

本地文生图使用插件(Stable Diffusion)

1. 插件下载&#xff08;github&#xff09; 1.1 直接Avaliable中点击安装&#xff08;方案一&#xff09; 1.2 Install from URL中输入URL&#xff08;方案二&#xff09; 1.3 直接下载复制到extensions目录&#xff08;方案三&#xff09; 2. 模型下载&#xff08;Huggingf…

鸿蒙-全屏播放页面(使用相对布局)---持续更新中

最终实现效果图&#xff1a; 实现步骤 创建FullScreenPlay.ets全品播放页面 并将其修改为启动页面。 全屏播放&#xff0c;屏幕必然横过来&#xff0c;所以要将窗口横过来。 编辑 src/main/ets/entryability/EntryAbility.ets 若写在/EntryAbility.ets中&#xff0c;则所有…

C++ 多线程简要讲解

std::thread是 C11 标准库中用于多线程编程的核心类&#xff0c;提供线程的创建、管理和同步功能。下面我们一一讲解。 一.构造函数 官网的构造函数如下&#xff1a; 1.默认构造函数和线程创建 thread() noexcept; 作用&#xff1a;创建一个 std::thread 对象&#xff0c;但…

每天认识一个设计模式-建造者模式:复杂对象的“装配式革命“

一、前言 在软件开发的广袤领域中&#xff0c;随着项目规模日益庞大、业务逻辑愈发复杂&#xff0c;对象的创建过程也变得千头万绪。 早期简单的对象创建方式&#xff0c;在面对复杂对象时&#xff0c;逐渐显露出代码臃肿、耦合度高、可维护性差等弊端&#xff0c;设计模式的…