后端程序员入门react笔记(六)- 讲透Promise与Fetch

js声明变量的三种方式

我们通常使用 var let 和const来声明js的变量,但是这三者有什么区别呢?

  • var的变量可以是全局的或者函数作用域,而let和const只能是块级作用域
  • var和let可以重新赋值,而const是不允许重新赋值的,
  • var可以在一个作用域内重新声明,let和const只能声明一次
  • 一般来说,建议使用 let 和 const 来声明变量,因为它们提供了更严格的作用域控制和可变性。var 仍然可以在某些情况下使用,例如在需要全局作用域的变量时。

js的异步编程

用过ajax请求的人应该都知道有这么一个参数async,即是否异步,如果是异步,则设置为true,如果是非异步,则为false,我们举例看一下

<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script>console.log(1);$.ajax({url: "./a.json",type: "post",dataType: "text",async: true,//异步data: {},success: function(data){console.log(2);}});console.log(3);
</script>
  • 结果返回的是1 3 2 ,即js并没有等待ajax的结果,而是继续往下执行代码,Ajax的返回结果是通过success回调函数调用的。如果把async设置为false,则结果是1 2 3
    在这里插入图片描述

回调地狱

那么这个时候来了一个需求,要求根据第一个Ajax的请求结果作为条件来发起第二个Ajax请求,然后以第二个Ajax的请求结果作为条件发送第三个Ajax请求,那么形式可能就是这样的

<script>$.ajax({url: "./a.json",type: "post",dataType: "text",async: true,success: function(data){$.ajax({url: "./a.json",type: "post",dataType: "text",async: true,success: function(data){$.ajax({url: "./a.json",type: "post",dataType: "text",async: true,success: function(data){}})}})}})
</script>

一层层的嵌套,这就是回调地狱。这即不好看,也不好写,逻辑更是混乱。那么怎么办呢?至少作为后端,我们取使用orm取数据的时候都会用到一种链式操作,比如Model(user).Where("email = ?",query.Email).Where("password = ?",utils.Md5Encode(query.PassWord)).First(user)。我们永远可以在之前的操作结果上加条件。那么js有没有这种写法呢?有的,这个东西就叫做promise

promise

Promise是ES6新增的一个类,可以翻译为承诺(许诺、契约等),promise允许你将异步操作链接在一起,并以同步的方式处理它们的结果。
既然是一个类,就会有构造函数,promise的构造函数叫executor,我们可以这样创建一个promise

const myPromise = new Promise((resolve, reject) => {// 这里是一些异步操作if (success) {resolve(result);} else {reject(error);}
});

处理promise

有两种处理promise的方法

  • .then():当 Promise 成功完成时调用。它接受一个回调函数,该函数将接收 Promise 的结果作为参数。
  • .catch():当 Promise 失败时调用。它接受一个回调函数,该函数将接收 Promise 的错误作为参数。注意,如果.then里面处理的err则catch无法再次捕捉
    注意,.then() 和 .catch() 回调总是返回一个新的 Promise,这使得可以链接 Promise。
var promise = new Promise(function(resolve, reject) {if (/* 异步操作成功 */){resolve(value);} else {reject(error);}
});
promise.then(function(value) {// 如果调用了resolve方法,执行此函数
}, function(value) {// 如果调用了reject方法,执行此函数
});

演示

<script>var getJSON = function (url) {//创建一个promise并返回return new Promise(function (resolve, reject) {//进行一些异步操作const client = new XMLHttpRequest();client.open("GET", url);client.onreadystatechange = handler;client.responseType = "json";client.setRequestHeader("Accept", "application/json");client.send();function handler() {if (this.readyState === 4) {if (this.status === 200) {//如果成功则执行resolveresolve(this.response);} else {//如果失败则执行resolvereject(new Error(this.statusText));}}};});};getJSON("./a.json").then(function(json) {console.log(json);}, function(error) {console.error('出错了', error);});
</script>

链式调用

Promise 可以链接在一起,形成一个链式调用:

myPromise1.then((result1) => {return myPromise2(result1);}).then((result2) => {// 处理最终结果}).catch((error) => {// 处理错误});

promise的状态

promise实例的状态有三种

  • pending: 初始状态,未执行
  • fulfilled: 操作完成
  • rejected: 操作失败

调用流程图

在这里插入图片描述

一道面试题

下面这道题目,输出结果是多少?

    console.log(1);new Promise(function (resolve, reject){console.log(2);reject(true);console.log(3);window.setTimeout(function (){console.log(4);resolve(false);}, 0);}).then(function(){console.log(5);}, function(){console.log(6);});console.log(7);
  • 接下来我们解析一下上面的代码,console.log(1)执行输出1,构造promise对象要先执行executor,输出console.log(2);异步调用reject(true);继续输出console.log(3);setTimeout也是异步调用,被放到事件队列。promise对象创建完毕,继续console.log(7);reject事件发起回调,执行console.log(6);setTimeout发起回调,执行 console.log(4);,由于reject之后 promise的状态无法再次被修改,resolve(false)不会改变状态,所以不执行,最终执行结果就是 1 2 3 7 6 4

fetch

如果你了解xhr,那么你就很容易明白fetch,因为fetch就是js原生支持的,xhr的替代方案。Fetch被称为下一代 Ajax 技术,采用 Promise 的方式来处理数据。它是一种简洁明了的API,比 XMLHttpRequest 更加简单易用。

fetch的初试

我们来简单实现一个fetch的demo,我们前面说了,是js原生的api,无需引入其他包

    let url="./a.json"fetch(url).then((res)=>{console.log(res);}).catch((err)=>{console.log(err);})
  • 我们查看输出,请求的返回值是一个json,但是这个fetch返回的response没有我们的数据啊,为什么?这我们就要说到了关注分离原则
    在这里插入图片描述

关注分离

关注分离是一种软件设计原则,旨在将不同的功能模块分离开来,使其各自专注于特定的任务。在 Web 开发中,这意味着将输入、输出和状态跟踪等不同方面的功能分离开来,以便更好地组织代码并提高可维护性。
比如咱们上面举例的这个fetch,response并不是说我获取到了数据,重点在于我链接服务成功了,服务器给我响应了,不管是404还是500还是200,只要服务器响应我了,我就认为我任务完成了。
在这里插入图片描述
那么我们怎么获取数据呢?那我们就要在这个基础上,继续获取promise里面的内容

    let url="./a.json"fetch(url).then((res)=>{console.log(res);//把结果作为promise返回return  res.json()}).then((json)=>{//处理上一个返回的promiseconsole.log(json);}).catch((err)=>{console.log(err);})

一个完整的fetch请求

一个完整的fetch,在url后面,其实还可以跟一个config对象,config对象属性如下,可以配置请求方式,data,headers等信息

{/** A BodyInit object or null to set request's body. */body?: BodyInit | null;/** A string indicating how the request will interact with the browser's cache to set request's cache. */cache?: RequestCache;/** A string indicating whether credentials will be sent with the request always, never, or only when sent to a same-origin URL. Sets request's credentials. */credentials?: RequestCredentials;/** A Headers object, an object literal, or an array of two-item arrays to set request's headers. */headers?: HeadersInit;/** A cryptographic hash of the resource to be fetched by request. Sets request's integrity. */integrity?: string;/** A boolean to set request's keepalive. */keepalive?: boolean;/** A string to set request's method. */method?: string;/** A string to indicate whether the request will use CORS, or will be restricted to same-origin URLs. Sets request's mode. */mode?: RequestMode;/** A string indicating whether request follows redirects, results in an error upon encountering a redirect, or returns the redirect (in an opaque fashion). Sets request's redirect. */redirect?: RequestRedirect;/** A string whose value is a same-origin URL, "about:client", or the empty string, to set request's referrer. */referrer?: string;/** A referrer policy to set request's referrerPolicy. */referrerPolicy?: ReferrerPolicy;/** An AbortSignal to set request's signal. */signal?: AbortSignal | null;/** Can only be null. Used to disassociate request from any Window. */window?: null;
}

async 和await

上面例子中,我们通过.then返回的promise再次.then ,这明显是有些繁琐的。那么怎么办?我们这里就可以用到async 和await,

    let url = "./a.json"async function getJson() {try {let res = await fetch(url);if (res.status !== 200) {throw new Error("请求失败")}const json = await res.json();console.log(json);} catch (e) {console.log(e);}}getJson()

那么这里面的async和await是什么意思呢?

  • async 关键字提供了一种更简单的方法来处理基于异步 Promise 的代码。在一个函数的开头添加 async,就可以使其成为一个异步函数。注意,async 函数总是返回一个 Promise 对象。
  • 在异步函数中,我们可以在调用一个返回 Promise 的函数之前使用 await 关键字。这使得代码在该点上等待,直到 Promise 被完成,这时 Promise 的响应被当作返回值,或者被拒绝的响应被作为错误抛出。这样我们就能够编写像同步代码一样的异步函数,注意,只能在 async 函数内使用 await 关键字,用于等待 Promise 对象 resolved 后返回结果。
  • await 会暂停 async 函数的执行,等待 Promise 返回结果,然后恢复函数执行并返回数据。
  • await 表达式如果抛出错误,会被捕获并返回 Promise 对象的 reject 状态。

promise的并行调用和链式调用示例

<script>let url1 = "./a1.json"let url2 = "./a2.json"let url3 = "./a3.json"async function getJson1(n) {console.log(n);try {let res = await fetch(url1);if (res.status !== 200) {throw new Error("请求失败")}return res.json();} catch (e) {console.log(e);}}async function getJson2(n) {console.log(n);try {let res = await fetch(url2);if (res.status !== 200) {throw new Error("请求失败")}return res.json();} catch (e) {console.log(e);}}async function getJson3(n) {console.log(n);try {let res = await fetch(url3);if (res.status !== 200) {throw new Error("请求失败")}return res.json();} catch (e) {console.log(e);}}//并行执行多个异步操作async function getAll(){//等待所有执行完毕let res= await Promise.all([getJson1(1), getJson2(2), getJson3(3)])let total=res[0].age+res[1].age+res[2].ageconsole.log(total);return total;}getAll()//链式调用 根据前面的结果调用下一个async function chain(){let init=0let res1=await getJson1(init);let res2=await getJson2(res1.age);let res3=await getJson3(res2.age);console.log(res3.age);}chain()</script>

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

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

相关文章

【王道数据结构】【chapter7查找】【P285t5】

线性表中各节点的检索概率不等时&#xff0c;可用如下策略提高顺序检索的效率&#xff1b;若找到指定的结点&#xff0c;则将该结点和其前驱结点&#xff08;若存在&#xff09;交换&#xff0c;使得经常被访问的结点尽量位于表的前端。试设计在顺序结构和链式结构的线性表盘上…

python中集合(Set)和列表(List)性能比较

文章目录 引言1. Set和List2. 性能对比3. 总结 引言 在当今的软件开发过程中&#xff0c;Python 已经成为了一种极为流行的编程语言&#xff0c;得益于其简洁的语法和强大的库支持。在 Python 中&#xff0c;列表&#xff08;List&#xff09;和集合&#xff08;Set&#xff0…

敏捷开发中如何写好用户故事?

什么是用户故事&#xff1f; 用户故事&#xff08;user story&#xff09;是一个用来确认用户和用户需求的简短描述&#xff0c;作为什么用户&#xff0c;希望如何&#xff0c;这样做的目的或者价值何在。用户故事在软件研发中又被描述为需求。用户故事通常的格式为&#xff1…

STL容器之list

​ 1.封装除了对数据的保护、更好地管理数据之外&#xff0c;还有实现了对上层的统一&#xff1b; ​ 2.类模板参数的不同&#xff0c;一方面是为了实例化出来不同的类&#xff0c;另一方面是为了实现类的成员函数的不同&#xff1b; 一、认识list ​ 1.list是一种带头双向循…

java高并发场景面试题,干货来袭

为什么阿里巴巴的持久层抛弃hibernate&#xff0c;采用MyBatis框架&#xff1f; 原因大概有以下4点&#xff1a; 尤其是需要处理大量数据或者大并发情况的网站服务&#xff0c;这也阿里选择MyBatis的原因。 MyBatis整体架构 不多讲&#xff0c;先看目录图 MyBatis源码笔记文档…

捕获在野SMBGhost本地提权攻击样本

前言 从Windows10 v1903/Windows Server v1903开始&#xff0c;微软在协议SMB3.1.1中开启了对数据压缩传输的支持&#xff0c;但是由于SMB没有正确处理压缩的数据包&#xff0c;在客户端/服务端解压数据的时候&#xff0c;没有对COMPRESSIN_TRANSFORM_HEADE结构进行安全校验&a…

【mysql 数据库事务】开启事务操作数据库,写入失败后,不回滚,会有问题么? 这里隐藏着大坑,复试,面试时可以镇住面试老师!!!!

建表字段: CREATE TABLE user (id INT(11) NOT NULL AUTO_INCREMENT,nickname VARCHAR(32) NOT NULL COLLATE utf8mb4_general_ci,email VARCHAR(32) NOT NULL COLLATE utf8mb4_general_ci,status SMALLINT(6) UNSIGNED NULL DEFAULT NULL,password VARCHAR(256) NULL DEFAULT…

Netty入门指南:从零开始的异步网络通信

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 Netty入门指南&#xff1a;从零开始的异步网络通信 前言Netty简介由来&#xff1a;发展历程&#xff1a;异步、事件驱动的编程模型&#xff1a; 核心组件解析通信协议高性能特性异步编程范式性能优化与…

C++ stack queue详解以及模拟实现

目录 1.stack的使用 1.1stack的定义 1.2stack的使用 1.3stack的构造 2.stack底层模拟实现 3.queue的使用 3.1queue的定义 3.2queue的使用 4.queue底层模拟实现 1.stack的使用 1.1stack的定义 1. stack是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环…

关于 cocos creator 如何打包抖音字节小游戏步骤一

1、cocos creator打开引擎&#xff0c;在顶部选择构建之后&#xff0c;在选择点击构建(ps:具体看项目组的大小&#xff0c;如果是一个简单的不多资源一般不到一分钟&#xff0c;如果项目很大&#xff0c;就至少半个小时以上)&#xff0c;之后 成功构建之后如下所示&#xff1a;…

修改Qt生成iOS应用的原生底层,编译QtBase下的ios子模块

1.下载Qt源码 2.找到ios.pro子工程 3.使用QtCreaor12打开ios.pro工程 4.出现工程下只有一个.pro文件解决 复制修改好的toolchain.prf文件进行替换. 修改方法:

分布式调度平台XXL-JOB

相对来说&#xff0c;xxl-job中心式的调度平台轻量级&#xff0c;开箱即用&#xff0c;操作简易&#xff0c;上手快&#xff0c;与SpringBoot有非常好的集成&#xff0c;而且监控界面就集成在调度中心&#xff0c;界面又简洁&#xff0c;对于企业维护起来成本不高&#xff0c;还…

论文阅读-CheckFreq:频繁、精细的DNN检查点操作。

论文名称&#xff1a;CheckFreq: Frequent, Fine-Grained DNN Checkpointing. 摘要 训练深度神经网络(DNNs)是一项资源密集且耗时的任务。在训练过程中&#xff0c;模型在GPU上进行计算&#xff0c;重复地学习权重&#xff0c;持续多个epoch。学习到的权重存在GPU内存中&…

网站三合一缩略图片介绍展示源码

网站三合一缩略图片介绍展示源码&#xff0c;PHP源码&#xff0c;运行需要php环境支持&#xff0c;效果截图如下 蓝奏云下载&#xff1a;https://wfr.lanzout.com/ihY8y1pgim6j

SpringMVC了解

1.springMVC概述 Spring MVC&#xff08;Model-View-Controller&#xff09;是基于 Java 的 Web 应用程序框架&#xff0c;用于开发 Web 应用程序。它通过将应用程序分为模型&#xff08;Model&#xff09;、视图&#xff08;View&#xff09;和控制器&#xff08;Controller&a…

daydayEXP: 支持自定义Poc文件的图形化漏洞利用工具

daydayEXP: 支持自定义Poc文件的图形化漏洞利用工具 基于java fx写的一款支持加载自定义poc文件的、可扩展的的图形化渗透测试框架。支持批量漏洞扫描、漏洞利用、结果导出等功能。 使用 经过测试,项目可在jdk8环境下正常使用。jdk11因为缺少一些必要的组件,所以jdk11版本工…

vue2+elementui上传照片(el-upload 超简单)

文章目录 element上传附件&#xff08;el-upload 超详细&#xff09;代码展示html代码data中methods中接口写法 总结 element上传附件&#xff08;el-upload 超详细&#xff09; 这个功能其实比较常见的功能&#xff0c;后台管理系统基本上都有&#xff0c;这就离不开element的…

Rocky Linux 运维工具 mv

一、mv的简介 ​​mv​是Linux系统中的命令&#xff0c;用于移动文件或重命名文件。它可以在同一文件系统内将文件从一个目录移动到另一个目录&#xff0c;也可以修改文件的名称。 二、mv的参数说明 1、 三、mv的实战示例 1、重命名 ###查看目录/root/下的文件列表 [rootloc…

【前端入门】设计模式+单多页+React

设计模式是一种解决特定问题的经验总结&#xff0c;它提供了经过验证的解决方案&#xff0c;可以在软件开发过程中使用。设计模式可以帮助前端开发人员更有效地组织和管理代码&#xff0c;并提供一种共享的语言和框架&#xff0c;以便与其他开发人员进行交流。 以下是一些常见…

可观测性在威胁检测和取证日志分析中的作用

在网络中&#xff0c;威胁是指可能影响其平稳运行的恶意元素&#xff0c;因此&#xff0c;对于任何希望避免任何财政损失或生产力下降机会的组织来说&#xff0c;威胁检测都是必要的。为了先发制人地抵御来自不同来源的任何此类攻击&#xff0c;需要有效的威胁检测情报。 威胁…