认识 Promise

认识 Promise

前言:为什么会出现 Promise?

最常见的一个场景就是 ajax 请求,通俗来说,由于网速的不同,可能你得到返回值的时间也是不同的,这个时候我们就需要等待,结果出来了之后才知道怎么样继续下去。

在 ajax 的原生实现中,利用了 onreadystatechange 事件,当该事件触发并且符合一定条件时,才能拿到想要的数据,之后才能开始处理数据,这样做看上去并没有什么麻烦,但如果这个时候,我们还需要另外一个 ajax 请求,这个新 ajax 请求的其中一个参数,得从上一个 ajax 请求中获取,这个时候我们就不得不等待上一个接口请求完成之后,再请求后一个接口

let xhr = new XMLHttpRequest();
xhr.open('get', 'https://...');
xhr.send();
xhr.onreadystatechange = function () {if (xhr.readyState === 4) {if (xhr.status >= 200 && xhr.status < 300) {console.log(xhr.responseText)//伪代码....let xhr = new XMLHttpRequest();xhr.open('get','http://www.xx.com?a'+xhr.responseText);xhr.send();xhr.onreadystatechange = function(){if(xhr.readyState === 4){if(xhr.status>=200 && xhr.status<300){console.log(xhr.responseText)}}}}}
}

当出现第三个 ajax(甚至更多)仍然依赖上一个请求时,我们的代码就变成了一场灾难。

这场灾难,往往也被称为回调地狱

因此我们需要一个叫做 Promise 的东西,来解决这个问题,当然,除了回调地狱之外,还有个非常重要的需求就是:为了代码更加具有可读性和可维护性,我们需要将数据请求与数据处理明确的区分开来

上面的写法,是完全没有区分开,当数据变得复杂时,也许我们自己都无法轻松维护自己的代码了。这也是模块化过程中,必须要掌握的一个重要技能,请一定重视。

1. Promise 是什么?

Promise 是异步编程的一种解决方案,比传统的解决方案回调函数更合理、更强大。

ES6 将其写进了语言标准,统一了用法,原生提供了 Promise 对象。

指定回调函数的方式也变得更加灵活易懂,也解决了异步回调地狱的问题

旧方案是单纯使用回调函数,常见的异步操作有:定时器、fs 模块、ajax、数据库操作

  • 从语法上说,Promise 是一个构造函数;
  • 从功能上说,Promise 对象用来封装一个异步操作并可以获取其成功 / 失败的结果值。

2. Promise 的优点

  1. 指定回调函数的方式更加灵活

    1. 旧的方法:必须在启动异步任务前指定

    2. promise:启动异步任务 -> 返回 promise 对象 -> 给 promise 对象绑定回调函数

      (甚至可以在异步任务结束后指定多个)

  2. 可以解决回调地狱问题,支持链式调用

    1. 什么是回调地狱?

      回调函数嵌套调用,外部回调函数异步执行的结果是嵌套的回调执行的条件

    2. 回调地狱的缺点?

      不便于阅读、不便于异常处理

    3. 解决方案?

      promise链式调用

    4. 终极解决方案

      async / await

3. 定义 Promise 对象

new Promise((resolve, reject) => { ... });

3.1 Promise 实例对象的两个属性

  1. PromiseState

    此属性为 promise 对象的状态属性。

    • fulfilled:成功的状态
    • rejected:失败的状态
    • pending:初始化的状态

    【注】状态只能由 pending -> fulfilled 或是 pending -> rejected

  2. PromiseResult

    此属性为 promise 对象的结果值(resolve 以及 reject 函数的形参值)

3.2 Promise 实例对象的两个参数

  1. resolve

    修改 promise 对象的状态,由 pending 修改为 fulfilled;

    将实参设置到这个属性 PromiseResult 中。

  2. reject

    修改 promise 对象的状态,由 pending 修改为 rejected;

    将实参设置到这个属性 PromiseResult 中。

let p = new Promise((resolve, reject) => {// 调整状态// reject(new Error("error")); // 状态为 rejectedresolve("success"); // 状态为 resolved
});
console.log(p); // Promise { <pending> }

4. Promise 对象的状态

Promise 对象通过自身的状态来控制异步操作,Promise 实例具有三种状态.

  1. 异步操作未完成:pending
  2. 异步操作成功:fulfilled
  3. 异步操作失败:rejected

这三种的状态的变化途径只有两种

  • 从 pending(未完成)到 fulfilled(成功)
  • 从 pending(未成功)到 rejected(失败)

一旦状态发生变化,就凝固了,不会再有新的状态变化,这也是 Promise 这个名字的由来,它的英语意思 “承诺”,一旦承诺生效,就不得再改变了,这也意味着 Promise 实例的状态变化只可能发生一次

在 Promise 对象的构造函数中,将一个函数作为第一个参数。而这个函数,就是用来处理 Promise 的状态变化。

上面的 resolve 和 reject 都为一个函数,他们的作用分别是将状态修改为 resolved 或 rejected。

因此,Promise 的最终结果只有两种情况:

  1. 异步操作成功,Promise 实例传回一个值(value),状态变为 fulfilled;
  2. 异步操作失败,Promise 实例抛出一个错误(error),状态变为 rejected

5. then 方法(重要)

实例化 Promise 时,使用回调函数作为参数,回调函数通常有两个参数:

  1. resolve 参数

    当执行到 resolve( ... ) 时,会调用 then 方法中的第一个参数(回调);

  2. reject 参数

    当执行到 reject( ... ) 时,会调用 then 方法中的第二个参数(回调);

then 方法中通常有两个回调函数作为参数,第一个回调在成功时(resolve)调用,第二个回调在出错时(reject)调用,第二个参数可以省略。

5.1 then 方法返回结果

调用 then 方法的返回结果是 Promise 对象,对象状态由回调函数的执行结果决定

  1. 返回结果是非 Promise 类型的属性

    返回状态 resolved(成功),返回值为对象成功的值

    const result = p.then((data) => {console.log(data);return 123;},(error) => { console.warn(error); }
    );console.log(result); // 返回值为 123
    

    如果未使用 return 进行返回,则返回值为 undefined。

  2. 返回 Promise 对象

    返回值和返回状态均由返回的 promise 对象的返回值和状态决定

    const result = p.then((data) => {console.log(data);return new Promise((resolve, reject) => {resolve("ok");// reject("出错了");});},(error) => { console.warn(error); }
    );
    console.log(result); // 返回状态为 resolved,返回值为 ok
    // console.log(result); // 返回状态为 rejected,返回值为 出错了
    
  3. 抛出错误

    返回状态 rejected(失败)

    const result = p.then((data) => {console.log(data);// throw new Error("出错了");throw "出错了";},(error) => { console.warn(error); }
    );console.log(result); // 返回状态为 rejected,返回值为 出错了
    

5.2 then 方法的链式调用

由于 promise 可以返回 promise 对象,因此可以进行链式调用

// 链式调用
p.then((data) => {},(error) => {}
).then((data) => {},// 失败回调可以省略
)...;

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

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

相关文章

纯c++实现transformer 训练+推理

项目地址 https://github.com/freelw/cpp-transformer C 实现的 Transformer 这是一个无需依赖特殊库的 Transformer 的 C 实现&#xff0c;涵盖了训练与推理功能。 本项目使用C复刻了《Dive into Deep Learning》中关于 Transformer 的第 11 章11.7小节点内容。构建了一个英…

Go 语言规范学习(7)

文章目录 Built-in functionsAppending to and copying slicesClearCloseManipulating complex numbersDeletion of map elementsLength and capacityMaking slices, maps and channelsMin and maxAllocationHandling panicsBootstrapping PackagesSource file organizationPac…

Python Cookbook-5.1 对字典排序

任务 你想对字典排序。这可能意味着需要先根据字典的键排序&#xff0c;然后再让对应值也处于同样的顺序。 解决方案 最简单的方法可以通过这样的描述来概括:先将键排序&#xff0c;然后由此选出对应值: def sortedDictValues(adict):keys adict.keys()keys.sort()return …

Git Rebase 操作中丢失提交的恢复方法

背景介绍 在团队协作中,使用 Git 进行版本控制是常见实践。然而,有时在执行 git rebase 或者其他操作后,我们可能会发现自己的提交记录"消失"了,这往往让开发者感到恐慌。本文将介绍几种在 rebase 后恢复丢失提交的方法。 问题描述 当我们执行以下操作时,可能…

C语言基础要素(019):输出ASCII码表

计算机以二进制处理信息&#xff0c;但二进制对人类并不友好。比如说我们规定用二进制值 01000001 表示字母’A’&#xff0c;显然通过键盘输入或屏幕阅读此数据而理解它为字母A&#xff0c;是比较困难的。为了有效的使用信息&#xff0c;先驱者们创建了一种称为ASCII码的交换代…

鸿蒙定位开发服务

引言 鸿蒙操作系统&#xff08;HarmonyOS&#xff09;作为面向万物互联时代的分布式操作系统&#xff0c;其定位服务&#xff08;Location Kit&#xff09;为开发者提供了多场景、高精度的位置能力支持。本文将从技术原理、开发流程到实战案例&#xff0c;全面解析鸿蒙定位服务…

rknn_convert的使用方法

rknn_convert是RKNN-Toolkit2提供的一套常用模型转换工具&#xff0c;通过封装上述API接口&#xff0c;用户只需编辑模型对应的yml配置文件&#xff0c;就可以通过指令转换模型。以下是如何使用rknn_convert工具的示例命令以及支持的指令参数&#xff1a; python -m rknn.api.…

解决 axios get请求瞎转义问题

在Vue.js项目中&#xff0c;axios 是一个常用的HTTP客户端库&#xff0c;用于发送HTTP请求。qs 是一个用于处理查询字符串的库&#xff0c;通常与 axios 结合使用&#xff0c;特别是在处理POST请求时&#xff0c;将对象序列化为URL编码的字符串。 1. 安装 axios 和 qs 首先&a…

【XTerminal】【树莓派】Linux系统下的函数调用编程

目录 一、XTerminal下的Linux系统调用编程 1.1理解进程和线程的概念并在Linux系统下完成相应操作 (1) 进程 (2)线程 (3) 进程 vs 线程 (4)Linux 下的实践操作 1.2Linux的“虚拟内存管理”和stm32正式物理内存&#xff08;内存映射&#xff09;的区别 (1)Linux虚拟内存管…

torch 拆分子张量 分割张量

目录 unbind拆分子张量 1. 沿着第n个维度拆分&#xff08;即按“批次”拆分&#xff09; split分割张量 常用用法&#xff1a; 总结&#xff1a; unbind拆分子张量 import torchquaternions torch.tensor([[1, 2, 3, 4], [5, 6, 7, 8]]) result torch.unbind(quaternio…

【Linux】内核驱动学习笔记(二)

7、framebuffer驱动详解 7.1、什么是framebuffer (1)裸机中如何操作LCD (2)OS下操作LCD的难点 (3)framebuffer帧缓冲&#xff08;简称fb&#xff09;是linux内核中虚拟出的一个设备 (4)framebuffer向应用层提供一个统一标准接口的显示设备 (5)从驱动来看&#xff0c;fb是一个…

用 Docker Compose 与 Nginx 反向代理部署 Vikunja 待办事项管理系统

在高效管理日常任务和项目的过程中&#xff0c;开源待办事项工具 Vikunja 以其简洁、直观的设计和多视图支持受到越来越多用户的青睐。本文将详细介绍如何使用 Docker Compose 快速部署 Vikunja&#xff0c;并通过 Nginx 反向代理实现 HTTPS 访问&#xff0c;从而确保服务安全稳…

使用Python快速接入DeepSeek API的步骤指南

使用Python快速接入DeepSeek API的步骤指南 1. 前期准备 注册DeepSeek账号 访问DeepSeek官网注册账号 完成邮箱验证等认证流程 获取API密钥 登录后进入控制台 → API管理 创建新的API Key并妥善保存 安装必要库 pip install requests # 可选&#xff1a;处理复杂场景 pip…

Redis 主要能够用来做什么

Redis&#xff08;Remote Dictionary Server&#xff09;是一种基于内存的键值存储数据库&#xff0c;它的性能极高&#xff0c;广泛应用于各种高并发场景。以下是 Redis 常见的用途&#xff1a; 1. 缓存&#xff08;Cache&#xff09; 作用&#xff1a;存储热点数据&#xf…

印度股票实时数据API接口选型指南:iTick.org如何成为开发者优选

在全球金融数字化浪潮中&#xff0c;印度股票市场因其高速增长潜力备受关注。对于量化交易开发者、金融科技公司而言&#xff0c;稳定可靠的股票报价API接口是获取市场数据的核心基础设施。本文将深度对比主流印度股票API&#xff0c;并揭示iTick在数据服务领域的独特优势。 一…

24.多路转接-poll

poll也是一种linux中的多路转接的方案 解决select的fd有上限的问题解决select每次调用都要重新设置关心的fd poll函数接口 poll, ppoll - wait for some event on a file descriptor#include <poll.h>int poll(struct pollfd *fds, nfds_t nfds, int timeout);DESCRIP…

Linux 基础入门操作 前言 linux操作指令介绍

1 linux 目录介绍 Linux 文件系统采用层次化的目录结构&#xff0c;所有目录都从根目录 / 开始 1.1 核心目录 / (根目录) 整个文件系统的起点、包含所有其他目录和文件 /bin (基本命令二进制文件) 存放系统最基本的shell命令&#xff1a;如 ls, cp, mv, rm, cat 等&#…

Chrome开发者工具实战:调试三剑客

在前端开发的世界里&#xff0c;Chrome开发者工具就是我们的瑞士军刀&#xff0c;它集成了各种强大的功能&#xff0c;帮助我们快速定位和解决代码中的问题。今天&#xff0c;就让我们一起来看看如何使用Chrome开发者工具中的“调试三剑客”&#xff1a;断点调试、调用栈跟踪和…

函数柯里化(Currying)介绍(一种将接受多个参数的函数转换为一系列接受单一参数的函数的技术)

文章目录 柯里化的特点示例普通函数柯里化实现使用Lodash进行柯里化 应用场景总结 函数柯里化&#xff08;Currying&#xff09;是一种将接受多个参数的函数转换为一系列接受单一参数的函数的技术。换句话说&#xff0c;柯里化将一个多参数函数转化为一系列嵌套的单参数函数。 …

torch.nn中的非线性激活介绍合集——Pytorch中的非线性激活

1、nn.ELU 基本语法&#xff1a; class torch.nn.ELU(alpha1.0, inplaceFalse)按元素应用 Exponential Linear Unit &#xff08;ELU&#xff09; 函数。 论文中描述的方法&#xff1a;通过指数线性单元 &#xff08;ELU&#xff09; 进行快速准确的深度网络学习。 ELU 定义为…