【Web前端】Promise的使用
Promise是异步编程的核心概念之一。代表一个可能尚未完成的操作,并提供了一种机制来处理该操作最终的成功或失败。具体来说,Promise是由异步函数返回的对象,能够指示该操作当前所处的状态。
当Promise被创建时,它会处于“待定”(Pending)状态,这意味着操作尚未完成。在这个阶段,Promise对象可以通过其提供的方法来注册回调函数,以便在操作最终完成后进行相应的处理。一旦操作完成,Promise的状态会变为“已兑现”(Fulfilled),表示成功;或者变为“已拒绝”(Rejected),表示失败。
除了基本的状态管理,Promise还提供了链式调用的能力,使得开发者可以以更加清晰和可读的方式进行异步操作的组合。例如,可以使用.then()方法处理成功的结果,使用.catch()方法处理错误,甚至可以通过.finally()方法执行一些清理工作,无论操作是成功还是失败。

一、什么是 Promise
Promise 是一个代表异步操作最终完成(或失败)及其结果值的对象。它有三种状态:
- Pending(待定): 初始状态,既不是成功,也不是失败。
- Fulfilled(已兑现): 操作成功完成。
- Rejected(已拒绝): 操作失败。
一旦 Promise 被 fulfilled 或 rejected,它的状态就会被锁定,后续的状态无法再改变。
Promise 的基本构造
Promise是通过 new Promise() 构造函数创建的。这个构造函数接受一个执行器(executor)函数作为参数,该函数接收两个参数:resolve 和 reject。通过调用 resolve 来标记Promise对象状态为已兑现(fulfilled),而通过调用 reject 则将其标记为已拒绝(rejected)。
const myPromise = new Promise((resolve, reject) => {// 模拟异步操作const success = true; // 假设操作成功if (success) {resolve('操作成功'); // 标记Promise为已兑现} else {reject('操作失败'); // 标记Promise为已拒绝}
});
Promise 的使用
一旦创建了Promise对象,可以利用 then() 方法处理Promise对象状态为已兑现时的返回值,也可以使用 catch() 方法来处理Promise对象状态为已拒绝时的错误信息。
myPromise.then(result => {console.log(result); // 打印: 操作成功}).catch(error => {console.error(error); // 打印错误信息});
当Promise对象状态为已兑现时,then()方法会调用传入的回调函数并输出成功的信息;当Promise对象状态为已拒绝时,则会调用catch()方法中的回调函数输出错误信息。
二、使用 fetch() API
fetch() API 是一个现代的网络请求接口,广泛用于发起网络请求并处理响应。它返回一个 Promise,使得异步操作的管理变得更加简单和直观。fetch() 通常用于获取网络资源,如 RESTful API 的数据。
基本的 fetch() 使用
以下是使用 fetch() 发送 GET 请求并处理响应的基本示例:
fetch('https://api.example.com/data').then(response => {// 检查响应是否成功if (!response.ok) {throw new Error('网络响应失败');}return response.json(); // 解析 JSON 数据}).then(data => {console.log(data); // 输出返回的数据}).catch(error => {console.error('请求失败:', error); // 捕获并输出错误信息});
-
fetch() 函数向指定的 URL 发送了 GET 请求。 - 响应通过
.then() 方法处理。如果响应不正常(例如状态码不是 200-299),则会抛出一个错误。 - 如果响应成功,使用
response.json() 方法解析 JSON 格式的数据,并在随后的 .then() 中使用解析后的数据。
发送 POST 请求
除了发送 GET 请求外,fetch() 还可以用来发送 POST 请求。在发送 POST 请求时,可以传递一个包含请求体的配置对象。
fetch('https://api.example.com/data', {method: 'POST', // 指定请求方法为 POSTheaders: {'Content-Type': 'application/json' // 设置请求头部信息},body: JSON.stringify({ key: 'value' }) // 转换请求体为 JSON 字符串
})
.then(response => {// 检查响应状态if (!response.ok) {throw new Error('网络响应失败');}return response.json(); // 解析 JSON 数据
})
.then(data => {console.log(data); // 输出返回的数据
})
.catch(error => {console.error('请求失败:', error); // 捕获并输出错误信息
});
- 使用
method: 'POST' 指明请求类型。 - 设置请求头
Content-Type 为 application/json,表明请求体的格式。 - 使用
body 属性将请求体转换为 JSON 字符串,以便于服务器理解。
三、链式使用 Promise
Promise 提供了链式调用的能力,这意味着可以在一个 then() 处理程序中返回另一个 Promise,从而形成异步操作的链式结构。
链式调用
下面示例中,展示了如何使用 Promise 的链式调用来依次请求两个不同的数据资源:
fetch('https://api.example.com/data1').then(response => response.json()).then(data1 => {console.log('数据1:', data1);return fetch('https://api.example.com/data2'); // 返回另一个 Promise}).then(response => response.json()).then(data2 => {console.log('数据2:', data2);}).catch(error => {console.error('请求失败:', error);});
- 第一个
fetch() 请求获取第一个数据资源,通过 .then() 解析响应为 JSON 数据。 - 在第一个
.then() 处理程序中,我们输出第一个数据并返回另一个 fetch() 请求,以发起第二个异步操作。 - 第二个
fetch() 请求获取第二个数据资源,通过 .then() 解析响应为 JSON 数据。 - 最后一个
.then() 处理程序输出第二个数据。
工作原理
当一个 Promise 被 resolve 时,它会传递给下一个 .then() 处理程序。如果在 .then() 处理程序中返回一个新的 Promise,则当前 Promise 的状态将取决于此新 Promise 的状态。这样就形成了一条链,依次处理多个异步操作。
四、错误捕获
在使用 Promise 进行异步操作时,错误处理是非常重要的一部分。通过在 Promise 链中使用 catch() 方法,可以捕获整个链中发生的错误,并进行相应的处理。
错误处理
示例中展示了如何在一个 Promise 链中处理错误:
fetch('https://api.example.com/data1').then(response => {if (!response.ok) {throw new Error('网络响应失败');}return response.json();}).then(data1 => {console.log('数据1:', data1);return fetch('https://api.example.com/data2');}).then(response => {if (!response.ok) {throw new Error('网络响应失败');}return response.json();}).then(data2 => {console.log('数据2:', data2);}).catch(error => {console.error('请求失败:', error);});
- 每个
.then() 处理程序都会检查响应是否成功。如果不成功,则抛出一个 Error。 -
catch() 方法用于捕获所有发生的错误,包括前面任何一个 Promise 的错误。 - 如果任何一个 Promise 出现错误,后续的
.then() 处理程序会被跳过,直接执行 catch() 中的错误处理逻辑。
Promise 链中的任何一个 Promise 的错误都会传递到最近的 catch() 方法中。这样做可以确保整个链中的任何一个步骤出现问题时都能得到正确的处理。catch() 方法也可以用来统一处理整个链中的错误,使代码更加清晰和易于维护。
五、Promise 术语
讨论 Promise 中了解一些重要的术语很有帮助。以下是一些常见的 Promise 术语及其含义:
- Promise 实例: 通过
new Promise() 创建的对象,代表一个异步操作的最终完成或失败。 - Executor 函数: Promise 构造函数中传递的函数,定义了异步操作的行为和状态变化。
- then() 方法: 用于处理 Promise 对象的成功状态(fulfilled)的回调函数,接受一个成功的值作为参数。
- catch() 方法: 用于处理 Promise 对象的失败状态(rejected)的回调函数,接受一个错误作为参数。
- finally() 方法: 无论 Promise 的状态如何(成功或失败),都会执行的回调函数。
使用 finally()
下面的示例展示了如何使用 finally() 方法来进行清理工作,无论 Promise 是成功还是失败,finally() 中的回调都会被执行:
fetch('https://api.example.com/data').then(response => {if (!response.ok) {throw new Error('网络响应失败');}return response.json();}).then(data => {console.log(data);}).catch(error => {console.error('请求失败:', error);}).finally(() => {console.log('请求完成,无论成功或失败。');});
- 如果获取数据成功,数据将会被输出到控制台。
- 如果获取数据失败,错误信息将会被输出到控制台。
- 无论前面的 Promise 是成功还是失败,
finally() 中的回调都会被执行,用来进行一些清理工作或其他必要的操作。
六、合并多个 Promise
处理多个异步操作时,可以使用 Promise.all() 和 Promise.race() 这两种方法来组合多个 Promise 对象。
Promise.all()
Promise.all() 方法接收一个包含多个 Promise 的数组作为参数,只有当所有 Promise 都成功时,返回的 Promise 才会成功。如果其中任何一个 Promise 失败,则返回的 Promise 也会失败。
const promise1 = fetch('https://api.example.com/data1');
const promise2 = fetch('https://api.example.com/data2');Promise.all([promise1, promise2]).then(responses => {return Promise.all(responses.map(response => {if (!response.ok) {throw new Error('网络响应失败');}return response.json();}));}).then(data => {console.log('数据:', data);}).catch(error => {console.error('请求失败:', error);});
- 通过 Promise.all() 组合了两个获取数据的 Promise。
- 如果所有 Promise 都成功,我们会将获取的数据输出到控制台。
- 如果任何一个 Promise 失败(例如网络响应失败),则捕获并输出错误信息。
Promise.race()
Promise.race() 方法返回一个 Promise,该 Promise 只会在第一个 Promise 解决或拒绝时解决。即使其他 Promise 还没有完成,只要有一个 Promise 在之前完成或失败,race() 返回的 Promise 就会立即解决。
const promise1 = new Promise((resolve, reject) => {setTimeout(resolve, 100, '第一个 Promise 完成');
});
const promise2 = new Promise((resolve, reject) => {setTimeout(reject, 50, '第二个 Promise 失败');
});Promise.race([promise1, promise2]).then(result => {console.log(result); // 不会执行,因为 promise2 先失败}).catch(error => {console.error(error); // 输出: 第二个 Promise 失败});
- 创建了两个延迟的 Promise,一个成功一个失败。
- 使用 Promise.race() 来比较这两个 Promise,结果是第二个 Promise 失败,因此 catch() 方法被触发,输出失败的原因。
7. async 和 await
async 和 await 是 ES2017 引入,用于更简洁地处理 Promise。async 关键字用于定义异步函数,await 用于等待 Promise 解决。
使用 async 和 await
async function fetchData() {try {const response1 = await fetch('https://api.example.com/data1');if (!response1.ok) {throw new Error('网络响应失败');}const data1 = await response1.json();console.log('数据1:', data1);const response2 = await fetch('https://api.example.com/data2');if (!response2.ok) {throw new Error('网络响应失败');}const data2 = await response2.json();console.log('数据2:', data2);} catch (error) {console.error('请求失败:', error);}
}fetchData();
- 使用 async 定义了一个异步函数 fetchData(),里面包含多个 await 表达式来等待 Promise 解决,并处理返回的数据。
- 如果任何一个 Promise 解决失败,错误信息将被捕获并输出到控制台。
async 函数的返回值
async 函数总是返回一个 Promise,即使函数内没有显式返回值。下面的示例展示了这一点:
async function example() {return 'Hello, World!';
}example().then(message => {console.log(message); // 输出: Hello, World!
});
- async 函数 example() 返回一个字符串 'Hello, World!'。
- 虽然在函数内没有显式返回 Promise,但由于是 async 函数,最终返回的仍然是一个 Promise 对象。
我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=tfvwshelnu3w
相关文章:
【Web前端】Promise的使用
Promise是异步编程的核心概念之一。代表一个可能尚未完成的操作,并提供了一种机制来处理该操作最终的成功或失败。具体来说,Promise是由异步函数返回的对象,能够指示该操作当前所处的状态。 当Promise被创建时,它会处于“待定”&a…...
TDK推出第二代用于汽车安全应用的6轴IMU
近日,据外媒报道,TDK株式会社推出用于汽车安全应用的第二代6轴 IMU,即为TDK InvenSense SmartAutomotive MEMS传感器系列增加了IAM-20685HP和IAM-20689,为决策算法提供可靠的运动数据,并实时准确地检测车辆动态。这对于…...
免费S3客户端工具大赏
首发地址(欢迎大家访问):S3免费客户端工具大赏 1. S3 GUI GitHub地址:https://github.com/aminalaee/s3gui 简介:S3 GUI 是一款基于 Flutter 构建的免费开源 S3 桌面客户端,支持桌面、移动和网络平台。 特…...
前端访问后端实现跨域
背景:前端在抖音里做了一个插件然后访问我们的后端。显然在抖音访问其他域名肯定会跨域。 解决办法: 1、使用比较简单的jsonp JSONP 优点:JSONP 是通过动态创建 <script> 标签的方式加载外部数据,属于跨域数据请求的一种…...
TCP和UDP通信基础
目录 1. 套接字 (Socket) 2. 基于TCP通信的流程 服务器端 客户端 1. TCP通信API 1.1 创建套接字描述符socket 1.2 绑定IP和端口号bind 1.3 设置监听状态 listen 1.4 接受连接请求 accept 1.5 发送数据 send 1.6 接收数据 recv 2. TCP服务器代码示例 代码解释&…...
微服务中的技术使用与搭配:如何选择合适的工具构建高效的微服务架构
一、微服务架构中的关键技术 微服务架构涉及的技术非常广泛,涵盖了开发、部署、监控、安全等各个方面。以下是微服务架构中常用的一些技术及其作用: 1. 服务注册与发现 微服务架构的一个重要特性是各个服务是独立部署的,因此它们的地址&am…...
找出字符串第一个匹配项的下标
找出字符串第一个匹配项的下标 题目描述: 题解思路: 图上所示,利用字符滑动,如果匹配就字符开始移动;如果不匹配成功,则停止移动,并回到字符串刚开始匹配的字符下标前一个,为下一次…...
面向FWA市场!移远通信高性能5G-A模组RG650V-NA通过北美两大重要运营商认证
近日,全球领先的物联网整体解决方案供应商移远通信宣布,其旗下符合3GPP R17标准的新一代5G-A模组RG650V-NA成功通过了北美两家重要运营商认证。凭借高速度、大容量、低延迟、高可靠等优势,该模组可满足CPE、家庭/企业网关、移动热点、高清视频…...
Matlab实现北方苍鹰优化算法优化随机森林算法模型 (NGO-RF)(附源码)
目录 1.内容介绍 2.部分代码 3.实验结果 4.内容获取 1内容介绍 北方苍鹰优化算法(Northern Goshawk Optimization, NGO)是一种新颖的群智能优化算法,灵感源自北方苍鹰捕食时的策略。该算法通过模拟苍鹰的搜寻、接近和捕捉猎物的行为模式&am…...
搭建环境 配置编译运行 mpi-test-suite
1,编译安装 ucx 下载源码: $ git clone https://github.com/openucx/ucx.git $ git checkout v1.17.0 运行auto工具: $ ./autogen.sh $ ./autogen.sh 指所以运行两次是因为有时候第一次会失败,原因未查。 配置 ucx $ m…...
夜神模拟器启动报错:虚拟机启动失败 请进行修复 关闭hyper-v
不是关闭hyper-v的问题。 点那个没用。 解决办法: 我电脑win11(win10 win11都一样 )去安全中心-设备安全性 把内存完整性关了。 这还不够。 在右上角找系统信息 我发现VT显示没开 于是我去BIOS中开启VT 这个VT怎么开很简单。就是你F2 F1…...
投资策略规划最优决策分析
目录 一、投资策略规划问题详细 二、存在最优投资策略:每年都将所有钱投入到单一投资产品中 (一)状态转移方程 (二)初始条件与最优策略 (三)证明最优策略总是将所有钱投入到单一投资产品中…...
一篇保姆式虚拟机安装ubantu教程
前言: 本文将介绍在VMware安装ubantu,会的人可以试试上一篇介绍centos/ubantu安装docker环境,不同环境安装docker。一篇保姆式centos/unbantu安装docker 官网下载iso:Ubuntu 18.04.6 LTS (Bionic Beaver) 本次使用的版本是: 一&…...
缓冲区的奥秘:解析数据交错的魔法
目录 一、理解缓存区的好处 (一)直观性的理解 (二)缓存区的好处 二、经典案例分析体会 (一)文件读写流(File I/O Buffering) BufferedOutputStream 和 BufferedWriter 可以加快…...
CentOS 7.9 搭建本地Yum源
yum(Yellow Dog Updater,Modified)是一个在Fedora、Centos、RedHat中的Shell前端软件包管理器。基于RPM包管理,能够从指定的服务器自动下载RPM包并且安装,可以自动处理依赖关系,并且一次安装所有依赖的软件…...
【Python】爬虫实战:高效爬取电影网站信息指南(涵盖了诸多学习内容)
本期目录 1 爬取思路 2 爬虫过程 2.1 网址 2.2 查看网页代码 3 爬取数据 3.1 导入包 3.2 爬取代码 01 爬取思路 \*- 第一步,获取页面内容\*- 第二步:解析并获取单个项目链接 \*- 第三步:获取子页面内容 \*- 第四步:解析…...
MATLAB和C++及Python流式细胞术
🌵MATLAB 片段 流式细胞术(Flow Cytometry)是一种用于分析细胞或其他颗粒悬浮在流动介质中的方法。MATLAB 可以用来处理和分析流式细胞术的数据,例如用于数据预处理、可视化和分析。以下是一些常见的 MATLAB 处理流式细胞术数据的…...
Vue3 pinia使用
Pinia 是一个现代的状态管理库,专为 Vue 3 设计。它提供了一种简单、直观的方式来管理应用中的全局状态 (就是不同组件都希望去共享的一些变量,函数等)。Pinia 的设计灵感来自于 Vuex(Vue 2 的状态管理库),但进行了许多改进&#…...
tdengine学习笔记-建库和建表
目录 建库和建表 创建超级表 创建表 自动建表 创建普通表 多列模型 VS 单列模型 数据类型映射 示例程序汇总 在车联网领域的应用 1. 数据模型概述 2. 表结构设计 2.1 静态数据表 2.2 动态数据表 4. 查询数据 4.1 查询单个车辆的数据 4.2 查询多个…...
Django数据迁移出错,解决raise NodeNotFoundError问题
错误出现在: raise NodeNotFoundError(self.error_message, self.key, originself.origin) django.db.migrations.exceptions.NodeNotFoundError: Migration myApp.0003_alter_jobinfo_practise dependencies reference nonexistent parent node (myApp, 0002_renam…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...
NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
scikit-learn机器学习
# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...
elementUI点击浏览table所选行数据查看文档
项目场景: table按照要求特定的数据变成按钮可以点击 解决方案: <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...
