当前位置: 首页 > news >正文

【Web前端】Promise的使用

Promise是异步编程的核心概念之一。代表一个可能尚未完成的操作,并提供了一种机制来处理该操作最终的成功或失败。具体来说,Promise是由异步函数返回的对象,能够指示该操作当前所处的状态。

当Promise被创建时,它会处于“待定”(Pending)状态,这意味着操作尚未完成。在这个阶段,Promise对象可以通过其提供的方法来注册回调函数,以便在操作最终完成后进行相应的处理。一旦操作完成,Promise的状态会变为“已兑现”(Fulfilled),表示成功;或者变为“已拒绝”(Rejected),表示失败。

除了基本的状态管理,Promise还提供了链式调用的能力,使得开发者可以以更加清晰和可读的方式进行异步操作的组合。例如,可以使用.then()方法处理成功的结果,使用.catch()方法处理错误,甚至可以通过.finally()方法执行一些清理工作,无论操作是成功还是失败。

a3296ed54c5f4b6188aead8b3a9e4910.jpeg


一、什么是 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 桌面客户端,支持桌面、移动和网络平台。 特…...

前端访问后端实现跨域

背景&#xff1a;前端在抖音里做了一个插件然后访问我们的后端。显然在抖音访问其他域名肯定会跨域。 解决办法&#xff1a; 1、使用比较简单的jsonp JSONP 优点&#xff1a;JSONP 是通过动态创建 <script> 标签的方式加载外部数据&#xff0c;属于跨域数据请求的一种…...

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服务器代码示例 代码解释&…...

微服务中的技术使用与搭配:如何选择合适的工具构建高效的微服务架构

一、微服务架构中的关键技术 微服务架构涉及的技术非常广泛&#xff0c;涵盖了开发、部署、监控、安全等各个方面。以下是微服务架构中常用的一些技术及其作用&#xff1a; 1. 服务注册与发现 微服务架构的一个重要特性是各个服务是独立部署的&#xff0c;因此它们的地址&am…...

找出字符串第一个匹配项的下标

找出字符串第一个匹配项的下标 题目描述&#xff1a; 题解思路&#xff1a; 图上所示&#xff0c;利用字符滑动&#xff0c;如果匹配就字符开始移动&#xff1b;如果不匹配成功&#xff0c;则停止移动&#xff0c;并回到字符串刚开始匹配的字符下标前一个&#xff0c;为下一次…...

面向FWA市场!移远通信高性能5G-A模组RG650V-NA通过北美两大重要运营商认证

近日&#xff0c;全球领先的物联网整体解决方案供应商移远通信宣布&#xff0c;其旗下符合3GPP R17标准的新一代5G-A模组RG650V-NA成功通过了北美两家重要运营商认证。凭借高速度、大容量、低延迟、高可靠等优势&#xff0c;该模组可满足CPE、家庭/企业网关、移动热点、高清视频…...

Matlab实现北方苍鹰优化算法优化随机森林算法模型 (NGO-RF)(附源码)

目录 1.内容介绍 2.部分代码 3.实验结果 4.内容获取 1内容介绍 北方苍鹰优化算法&#xff08;Northern Goshawk Optimization, NGO&#xff09;是一种新颖的群智能优化算法&#xff0c;灵感源自北方苍鹰捕食时的策略。该算法通过模拟苍鹰的搜寻、接近和捕捉猎物的行为模式&am…...

搭建环境 配置编译运行 mpi-test-suite

1&#xff0c;编译安装 ucx 下载源码&#xff1a; $ git clone https://github.com/openucx/ucx.git $ ​git checkout v1.17.0 ​ 运行auto工具&#xff1a; $ ./autogen.sh $ ./autogen.sh 指所以运行两次是因为有时候第一次会失败&#xff0c;原因未查。 配置 ucx $ m…...

夜神模拟器启动报错:虚拟机启动失败 请进行修复 关闭hyper-v

不是关闭hyper-v的问题。 点那个没用。 解决办法&#xff1a; 我电脑win11&#xff08;win10 win11都一样 &#xff09;去安全中心-设备安全性 把内存完整性关了。 这还不够。 在右上角找系统信息 我发现VT显示没开 于是我去BIOS中开启VT 这个VT怎么开很简单。就是你F2 F1…...

投资策略规划最优决策分析

目录 一、投资策略规划问题详细 二、存在最优投资策略&#xff1a;每年都将所有钱投入到单一投资产品中 &#xff08;一&#xff09;状态转移方程 &#xff08;二&#xff09;初始条件与最优策略 &#xff08;三&#xff09;证明最优策略总是将所有钱投入到单一投资产品中…...

一篇保姆式虚拟机安装ubantu教程

前言&#xff1a; 本文将介绍在VMware安装ubantu&#xff0c;会的人可以试试上一篇介绍centos/ubantu安装docker环境,不同环境安装docker。一篇保姆式centos/unbantu安装docker 官网下载iso:Ubuntu 18.04.6 LTS (Bionic Beaver) 本次使用的版本是&#xff1a; 一&…...

缓冲区的奥秘:解析数据交错的魔法

目录 一、理解缓存区的好处 &#xff08;一&#xff09;直观性的理解 &#xff08;二&#xff09;缓存区的好处 二、经典案例分析体会 &#xff08;一&#xff09;文件读写流&#xff08;File I/O Buffering&#xff09; BufferedOutputStream 和 BufferedWriter 可以加快…...

CentOS 7.9 搭建本地Yum源

yum&#xff08;Yellow Dog Updater&#xff0c;Modified&#xff09;是一个在Fedora、Centos、RedHat中的Shell前端软件包管理器。基于RPM包管理&#xff0c;能够从指定的服务器自动下载RPM包并且安装&#xff0c;可以自动处理依赖关系&#xff0c;并且一次安装所有依赖的软件…...

【Python】爬虫实战:高效爬取电影网站信息指南(涵盖了诸多学习内容)

本期目录 1 爬取思路 2 爬虫过程 2.1 网址 2.2 查看网页代码 3 爬取数据 3.1 导入包 3.2 爬取代码 01 爬取思路 \*- 第一步&#xff0c;获取页面内容\*- 第二步&#xff1a;解析并获取单个项目链接 \*- 第三步&#xff1a;获取子页面内容 \*- 第四步&#xff1a;解析…...

MATLAB和C++及Python流式细胞术

&#x1f335;MATLAB 片段 流式细胞术&#xff08;Flow Cytometry&#xff09;是一种用于分析细胞或其他颗粒悬浮在流动介质中的方法。MATLAB 可以用来处理和分析流式细胞术的数据&#xff0c;例如用于数据预处理、可视化和分析。以下是一些常见的 MATLAB 处理流式细胞术数据的…...

Vue3 pinia使用

Pinia 是一个现代的状态管理库&#xff0c;专为 Vue 3 设计。它提供了一种简单、直观的方式来管理应用中的全局状态 (就是不同组件都希望去共享的一些变量,函数等)。Pinia 的设计灵感来自于 Vuex&#xff08;Vue 2 的状态管理库&#xff09;&#xff0c;但进行了许多改进&#…...

tdengine学习笔记-建库和建表

目录 建库和建表 创建超级表​ 创建表​ 自动建表​ 创建普通表​ 多列模型 VS 单列模型​ 数据类型映射​ 示例程序汇总​ 在车联网领域的应用 1. 数据模型概述 2. 表结构设计 2.1 静态数据表 2.2 动态数据表 4. 查询数据 4.1 查询单个车辆的数据 4.2 查询多个…...

Django数据迁移出错,解决raise NodeNotFoundError问题

错误出现在&#xff1a; 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…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

逻辑回归:给不确定性划界的分类大师

想象你是一名医生。面对患者的检查报告&#xff08;肿瘤大小、血液指标&#xff09;&#xff0c;你需要做出一个**决定性判断**&#xff1a;恶性还是良性&#xff1f;这种“非黑即白”的抉择&#xff0c;正是**逻辑回归&#xff08;Logistic Regression&#xff09;** 的战场&a…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容

基于 ​UniApp + WebSocket​实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配​微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

&#x1f31f; 什么是 MCP&#xff1f; 模型控制协议 (MCP) 是一种创新的协议&#xff0c;旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议&#xff0c;它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

Java入门学习详细版(一)

大家好&#xff0c;Java 学习是一个系统学习的过程&#xff0c;核心原则就是“理论 实践 坚持”&#xff0c;并且需循序渐进&#xff0c;不可过于着急&#xff0c;本篇文章推出的这份详细入门学习资料将带大家从零基础开始&#xff0c;逐步掌握 Java 的核心概念和编程技能。 …...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建

华为云FlexusDeepSeek征文&#xff5c;DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色&#xff0c;华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型&#xff0c;能助力我们轻松驾驭 DeepSeek-V3/R1&#xff0c;本文中将分享如何…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

Spring AI与Spring Modulith核心技术解析

Spring AI核心架构解析 Spring AI&#xff08;https://spring.io/projects/spring-ai&#xff09;作为Spring生态中的AI集成框架&#xff0c;其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似&#xff0c;但特别为多语…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在 GPU 上对图像执行 均值漂移滤波&#xff08;Mean Shift Filtering&#xff09;&#xff0c;用于图像分割或平滑处理。 该函数将输入图像中的…...