【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 对象。

 

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

EI检索!2024年大数据与数据挖掘会议(BDDM 2024)全解析!

第二届大数据与数据挖掘国际会议(BDDM 2024)将于2024年12月13-15日在武汉举行,已启动第二轮征稿,截稿2024年11月30日。邀请学者探讨大数据与数据挖掘进展,可在线投稿及AC学术中心查看详情。 大会官网:www.i…

基于java+ssm+Vue的校园美食交流系统设计与实现

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: Springboot mybatis Maven mysql5.7或8.0等等组成&#x…

关于 MSVCP110.dll 缺失的解决方案

背景:之前使用 PR(Adobe Premiere) 从来没有遇到过这样的问题。今天重装系统后(window 10),想要重新安装以前的软件时,遇到了以下 DLL 文件缺失的错误。 解决方案: 可以到微软官网的…

Python小游戏27——飞翔的小鸟

首先,你需要确保已经安装了Pygame库。如果还没有安装,可以通过以下命令进行安装: 【bash】 pip install pygame 游戏的代码: 【python】 import pygame import random # 初始化Pygame pygame.init() # 设置屏幕大小和标题 screen_…

【Three.js基础学习】24. shader patterns

前言 课程回顾: ShaderMaterial 这里用的是着色器材质 所以顶点和片段着色器就不需要像原始着色器那样添加需要的属性 然后写 片段着色器需要属性 : 顶点 属性 -》变化 -》 片段中 顶点中的属性不需要声明 只需要声明传送的变量 例如 varying vec vUv; vUv uv; 补充…

构建客服知识库:企业效率提升的关键步骤

客服知识库是企业提升客户服务效率和质量的重要工具。它不仅帮助客服团队快速准确地回答客户问题,还能通过数据分析来优化服务流程和提升客户满意度。 1. 明确知识库的目标和范围 构建客服知识库的第一步是明确其目标和范围。这包括确定知识库的主要用户群体、需要…

运动汇 专业的比赛管理平台数据获取

在获取到运动汇的网站链接后,界面如图所示: 右键检查,我们会发现没有任何数据,只有当我们点开这些"第一单元"、"第二单元"等,数据才会加载出来; 由于我们只需要分析这一个网页并获取其中的数据&a…

免费送源码:Java+Springboot+MySQL Springboot多租户博客网站的设计 计算机毕业设计原创定制

Springboot多租户博客网站的设计 摘 要 博客网站是当今网络的热点,博客技术的出现使得每个人可以零成本、零维护地创建自己的网络媒体,Blog站点所形成的网状结构促成了不同于以往社区的Blog文化,Blog技术缔造了“博客”文化。本文课题研究的“…

Docker环境搭建Cloudreve网盘服务(附shell脚本一键搭建)

Docker搭建Cloudreve Cloudreve介绍: Cloudreve 是一个基于 ThinkPHP 框架构建的开源网盘系统,旨在帮助用户以较低的成本快速搭建起既能满足个人也能满足企业需求的网盘服务。Cloudreve 支持多种存储介质,包括但不限于本地存储、阿里云OSS、…

Macs Fan Control - 控制 Apple 计算机上的风扇

免费下载 提供 macOS 和 Windows (Boot Camp) 版本 https://apsgo.cn/joN0WG Mac 风扇控制 监视和控制 Apple 计算机上的风扇 实时监控风扇速度和温度传感器,包括第三方 HDD/SSD(使用 S.M.A.R.T.)。设置自定义 RP…

3.STM32之通信接口《精讲》之USART通信

本节将进行实战,基础了解请查看第二节(Whappy)开始背!! USART ---》全双工 异步/同步 点对点 USART:STM32自带硬件电路,通过配置相对应的寄存器来设置数据帧的发送,我们收发只需要…

无插件H5播放器EasyPlayer.js网页web无插件播放器选择全屏时,视频区域并没有全屏问题的解决方案

EasyPlayer.js H5播放器,是一款能够同时支持HTTP、HTTP-FLV、HLS(m3u8)、WS、WEBRTC、FMP4视频直播与视频点播等多种协议,支持H.264、H.265、AAC、G711A、MP3等多种音视频编码格式,支持MSE、WASM、WebCodec等多种解码方…

SPIRiT-Diffusion:基于自一致性驱动的加速MRI扩散模型|文献速递-基于深度学习的病灶分割与数据超分辨率

Title 题目 SPIRiT-Diffusion: Self-Consistency Driven Diffusion Model for Accelerated MRI SPIRiT-Diffusion:基于自一致性驱动的加速MRI扩散模型 01 文献速递介绍 磁共振成像(MRI) 在临床和研究领域被广泛应用。然而,其…

Vue3中一级导航栏的吸顶导航交互以及Pinia优化重复请求

一、前言 在日常的网站中,当鼠标滚轮往页面的底部滑动时,会出现顶部导航栏的隐藏,而出现新的导航栏显示,这就是一级导航栏的吸顶导航交互。本文当实现改模块功能的实现。 二、示例图 参考黑马程序员小兔仙儿PC端项目:…

JDK17源码系列-ArrayList源码解读

JDK17源码系列-ArrayList接口源码解读 1.List集合接口类图 2.ArrayList详细类图 ArrayList继承了AbstractList实现了List、Serializable等接口,实现Serializable接口使得ArrayList类的对象可以串行化,串行化后,对象可以进行网络传输&#x…

VBA学习笔记:点击单元格显示指定的列

应用场景: 表格中列数较多,特定条件下隐藏一些无关的列,只保留相关的列,使表格更加清晰。 示例:原表格如下 点击一年级,只显示一年级相关的科目: 点击二年级,只显示二年级相关的科…

RNN深度学习案例:LSTM火灾温度预测

本文为为🔗365天深度学习训练营内部文章 原作者:K同学啊 一 前期准备数据 1.导入数据 import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns from sklearn.preprocessing import MinMaxScaler from keras.lay…

nmap简单使用

nmap的基本功能 nmap有4个基本功能,分别是 端口扫描 主机探测 服务识别 系统识别 端口扫描 nmap 183.2.172.185 从图中可以看出开放了80和443端口 指定端口扫描 指定端口扫描使用-p参数,可以一次性扫描一个或多个或某个范围内的端口 nmap 183.…

python文件排序都有哪些方法

在python环境中提供两种排序方案:用库函数sorted()对字符串排序,它的对象是字符;用函数sort()对数字排序,它的对象是数字,如果读取文件的话,需要进行处理(把文件后缀名‘屏蔽’)。 …

uni-app快速入门(五)--判断运行环境及针对不同平台的条件编译

一、判断运行环境 在实际项目开发中,经常需要进行开发环境和生产环境的切换,uni-app可根据process.env.NODE_ENV判断当前运行环境是开发环境和生产环境,根据不同的环境调用不同的后台接口,具体实现方式: 在项目的static目录下建…