【Web前端】Promise的使用

news2024/11/17 19:02:50

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', // 指定请求方法为 POST
    headers: {
        '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.coloradmin.cn/o/2242347.html

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

相关文章

EEG+EMG学习系列 (2) :实时 EEG-EMG 人机界面的下肢外骨骼控制系统

[TOC]( EEGEMG学习系列(2):实时 EEG-EMG 人机界面的下肢外骨骼控制系统) 论文地址:https://ieeexplore.ieee.org/abstract/document/9084126 论文题目:Real-Time EEG–EMG Human–Machine Interface-Based Control System for a Lower-Limb Exoskeleton …

Spring Authorization Server OAuth2.1

Spring Authorization Server介绍 Spring Authorization Server 是一个框架,它提供了 OAuth 2.1 和 OpenID Connect 1.0 规范以及其他相关规范的实现。 它建立在 Spring Security 之上,为构建 OpenID Connect 1.0 身份提供者和 OAuth2 授权服务器产品提供…

《生成式 AI》课程 第3講 CODE TASK 任务3:自定义任务的机器人

课程 《生成式 AI》课程 第3講:訓練不了人工智慧嗎?你可以訓練你自己-CSDN博客 我们希望你创建一个定制的服务机器人。 您可以想出任何您希望机器人执行的任务,例如,一个可以解决简单的数学问题的机器人0 一个机器人&#xff0c…

Python知识点精汇!字符串:定义、截取(索引)和其内置函数

目录 一、字符串的定义 二、字符串的截取 1.截取干啥的 2.怎么用截取 3.打印多次 4.两个字符串拼接在一起 三、字符串内置函数 1.查询函数: (1)find(str,start,end) (2)index(str,start,end&#…

创建vue+electron项目流程

一个vue3和electron最基本的环境搭建步骤如下:// 安装 vite vue3 vite-plugin-vue-setup-extend less normalize.css mitt pinia vue-router npm create vuelatest npm i vite-plugin-vue-setup-extend -D npm i less -D npm i normalize.css -S &#xff0…

从0开始机器学习--Day27--主成分分析方法

主成分分析方法(Principal components analysis) 在降维算法中,比较普遍的是使用主成分分析方法(PCA) PCA算法简单示例 如图,假设我们有一个二维的特征,想要将其降为一维,简单的方法是寻找一条直线&#…

无效的目标发行版17和无法连接Maven进程问题

起因:我clean了一个模块的Maven想要重新下,他就开始报错。两次了都是这样。如果和我一样一开始都是好好的,直接找Maven的设置,在运行程序改,jre变成了11.它自己变成了我其他的jdk

【Android、IOS、Flutter、鸿蒙、ReactNative 】启动页

Android 设置启动页 自定义 splash.xml 通过themes.xml配置启动页背景图 IOS 设置启动页 LaunchScreen.storyboard 设置为启动页 storyboard页面绘制 Assets.xcassets 目录下导入图片 AppLogo Flutter 设置启动页 Flutter Android 设置启动页 自定义 launch_background.xm…

Java实现多线程编程

目录 一、创建线程 1.1.第一种方法:继承Thread类 1.2.第二种方法:实现Runnable接口 1.3.其他创建线程的方法 二、多线程的优势-增加运行速度 三、Thread类及常见方法 3.1 Thread常见的构造方法 3.2Thread的几个常见方法 3.2.1启动一个线程——sta…

【快速解决】kafka崩了,重启之后,想继续消费,怎么做?

目录 一、怎么寻找我们关心的主题在崩溃之前消费到了哪里? 1、一个问题: 2、查看消费者消费主题__consumer_offsets 3、一个重要前提:消费时要提交offset 二、指定 Offset 消费 假如遇到kafka崩了,你重启kafka之后&#xff0…

【设计模式】行为型模式(四):备忘录模式、中介者模式

《设计模式之行为型模式》系列,共包含以下文章: 行为型模式(一):模板方法模式、观察者模式行为型模式(二):策略模式、命令模式行为型模式(三):责…

GRE做题笔记(零散的个人经验)

locomotive机车By 1813, the Luddite resistance had all but vanished. all but表示“几乎完全”的程度,或者表示排除piston活塞attributed to 归因于how a sportsperson accounted for their own experience of stress 运动员如何解释自己的压力经历 ,…

【vmware+ubuntu16.04】vm虚拟机及镜像安装-tools安装包弹不出来问题

学习机器人这门课需要下载虚拟机,做一下记录 首先我下载的是vm虚拟机16, 下载版本可参考该文章课堂上我下载 的镜像是16.04,虚拟机安装教程和镜像添加可参考该博主 按照教程安装成功 安装tools,但是我的弹不出来那个压缩包&…

Redis设计与实现 学习笔记 第十七章 集群

Redis集群是Redis提供的分布式数据库方案,集群通过分片(sharding,水平切分)来进行数据共享,并提供复制和故障转移功能。 17.1 节点 一个Redis集群通常由多个节点(node)组成,在刚开…

第03章 文件编程

目标 了解Linux系统文件IO/标准IO基本概念掌握Linux系统文件IO/标准IO常用函数掌握Linux系统文件属性常用函数掌握Linux系统目录文件常用函数 3.1 Linux系统概述 3.1.1 预备知识(相关概念) (1)应用程序 和 内核程序 应用程序是…

51c大模型~合集42

我自己的原文哦~ https://blog.51cto.com/whaosoft/11859244 #猎户座 「草莓」即将上线,OpenAI新旗舰大模型曝光,代号「猎户座」 ChatGPT 要进化了? 本月初,OpenAI 创始人、CEO 山姆・奥特曼突然在 X 上发了一张照片&#xff0…

SpringBootTest常见错误解决

1.启动类所在包错误 问题 由于启动类所在包与需要自动注入的类的包不在一个包下: 启动类所在包: com.exmaple.test_02 但是对于需要注入的类却不在com.exmaple.test_02下或者其子包下,就会导致启动类无法扫描到该类,从而无法对…

初始JavaEE篇 —— 网络编程(2):了解套接字,从0到1实现回显服务器

找往期文章包括但不限于本期文章中不懂的知识点: 个人主页:我要学编程程(ಥ_ಥ)-CSDN博客 所属专栏:JavaEE 目录 TCP 与 UDP Socket套接字 UDP TCP 网络基础知识 在一篇文章中,我们了解了基础的网络知识,网络的出…

机器学习 AdaBoost 算法

AdaBoost 提升学习算法是通过训练多个弱分类算法实现一个强分类算法,做法非常朴素,在训练过程中,提供分类错误的数据权重,降低分类正确的权重,提高分类效果好的弱分类器权重,降低分类效果差的若分类器权重。…

C++编程技巧与规范-类和对象

类和对象 1. 静态对象的探讨与全局对象的构造顺序 静态对象的探讨 类中的静态成员变量(类类型静态成员) 类中静态变量的声明与定义&#xff08;类中声明类外定义&#xff09; #include<iostream> using namespace std;namespace _nmspl {class A{public:A():m_i(5){…