网络请求 - 异步编程详解

一、概述

网络管理模块主要提供以下功能:

  • HTTP数据请求:通过HTTP发起一个数据请求。
  • WebSocket连接:使用WebSocket建立服务器与客户端的双向连接。
  • Socket连接:通过Socket进行数据传输。

HTTP和WebSocket都是啥?

        比如我们去逛某宝的商品列表,从HTTP协议的角度来看,前端发送了一次HTTP请求,网站返回一次HTTP响应。不过从始至终服务器都不会主动给客户端发送消息请求(就像你喜欢的人从来不会主动找你一样),这就是HTTP协议的特点。

        又比如我们玩传奇一刀999的网页游戏,我们甚至全程都没有点一次鼠标,但是服务器就源源不断地将怪物的移动数据和攻击数据发给我们。这种服务器可以主动给客户端发送消息的可双向传输数据场景就是使用了WebSocket协议。

        至于Socket协议,套接字(socket)是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开、读写和关闭等操作。套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信。网络套接字是IP地址与端口的组合。它偏向于底层,与WebSocket的关系就如Java和JavaScript,可以说是除了名字相似之外没什么关系。


二、异步Promise

1、并发、并行、同步和异步

并发

并发是一个比较宽泛的概念,它单纯代表计算机可以执行多项任务

比如一个单核处理器,计算机可以通过分配时间片的方式,让一个任务运行一段时间后切换到另一个任务。不同的任务就这样交替反复的一直执行下去。这个过程也被称作是进程或者线程的上下文切换

并行 

对于多核处理器,计算机可以在不同的核心上真正的并行执行任务,而不用像分配时间片这样的伪同时执行任务

 

同步&异步

至于同步和异步,它们则是两种不同的编程模型

同步代表需要等到前一个任务完成之后才可以执行下一个任务,因此在同步中并没有并发或者并行的概念

异步则代表不同的任务之间并不会相互等待先后执行,也就是说执行任务A时也可以执行任务B

一个典型的实现异步的方式就是多线程编程(如Java)

但是对于某些编程语言如JavaScript它们本身是没有多线程概念的,不过通过它的函数回调(function callback)机制,依旧可以做到单线程的并发

比如在这个案例中,fetch函数用来获取资源,他并不是按照函数编写的顺序去等待addImage()方法执行完毕再输出console.log(),而是跳过了该方法继续执行下面的代码。当获取到资源之后回调函数才被执行。

 

 注意:再次强调,JavaScript从设计之初就是一个单线程的语言,这样虽然看起来是同时运行的,但其底层还是运行在一个线程上运行的并发。

不过虽然只有单个线程在执行,不过这种单线程的异步编程还是有不少优点的

 所有的操作都运行在同一个线程中,你无需考虑线程同步或资源竞争的问题,从源头上避免了多线程之间的频繁切换,降低了线程自身的开销。

2、回调函数

在JavaScript中有两种实现异步的方式,第一种就是回调函数

什么是回调函数?其实很简单,就是一个函数被当成参数被另一个函数调用而已

比如:

其缺点也很明显,比如setTimeout是js自带的一个定时器,可以在其中传入一个回调函数

假如我现在想要在回调函数中继续调用回调函数,就会变成这样 

 这种回调函数嵌套的代码使得整段代码变得极其的诡异和难看,这就叫回调地狱(Callback Hell)

为了解决这个问题Promise应运而生

3、Promise

Promise也是第二种实现异步的方式

在JavaScript中,Promise对象是用来处理异步操作的一种机制,它表示一个异步操作的最终完成或失败,并且可以链式地处理这些操作。Promise对象有三个状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。

let myPromise = new Promise((resolve, reject) => {// 异步操作,可以是Ajax请求、文件读取等// 如果操作成功,调用 resolve(value)// 如果操作失败,调用 reject(reason)
});myPromise.then((result) => {// 处理操作成功的情况
}).catch((error) => {// 处理操作失败的情况
});

在创建Promise对象时,你会得到一个具有reslove和reject两个参数的函数。这两个参数都是函数,用于改变Promise对象的状态。具体来说:

  • resolve函数用于将Promise对象从pending(进行中)变为fulfilled(已成功)。

通常,当异步操作成功完成时,就调用该函数,结束异步请求并传递操作的结果作为参数

const myPromise = new Promise((resolve, reject) => {// 异步操作成功resolve("操作成功");
});
  • reject函数用于将Promise对象的状态从pending(进行中)变为rejected(已失败)。

当异步操作发生错误或失败时,你会调用该函数,结束异步请求并传递错误信息作为参数

const myPromise = new Promise((resolve, reject) => {// 异步操作失败reject("发生错误");
});

所以也就是说,如果不在异步调用中使用这两个函数的话,当你在别的地方调用这个异步请求时它会一直处于进行中状态,这两个异步请求自然也是是没有返回值的,因此也不会执行后面的回调逻辑。

这里再次强调一遍:Promise本身是无法中止的,其本身只是一个状态机,存储三个状态(pending,resolved,rejected),一旦发出请求了,必须闭环,无法取消。如果你不使用resolve/reject函数那么这个 Promise 将永远保持在 pending 状态。这样的 Promise 并不会自动转变为 fulfilled 或 rejected。

 4、async和await

简单来说,async和await是基于Promise的一个语法糖,可以让异步操作更加简单明了。所以也就是说在理论上,async/await 语法与 Promise 的链式写法在性能上没有本质的区别。它们都基于 JavaScript 的异步执行模型,实际性能差异较小。

不过好处当然是有的,不然还用它干什么

简而言之,使用async和await可以替换Promise的链式写法,让异步代码写的看起来像同步代码一样;替换掉.then,而.catch就用try...catch取代掉

不同于Promise的链式写法,写在async/await中想要中断程序就很简单了,因为语义化非常明显,其实就和一般的function写法一样,想要中断的时候,直接return一个值就行,null,空,false都是可以的。

比如这段Promise的链式操作的TypeScript代码

使用了async与await语法糖之后就变成了

是不是感觉就像以前写的同步代码一样,一下就顺眼起来了

那它是怎么实现的呢?

他们俩是一对好夫妻,缺一不可,async必须声明的是一个function,如果声明别的await就会很生气觉得它是渣男,就不生效了(报错)

async声明的函数无论如何都会返回一个Promise,比如

这是因为async将它自动解析成了Promise.resolve(),也就是说,相当于这段代码的效果

await是可以提供等同于"同步效果"的等待异步返回能力的语法糖

顾名思义,就是等一会。等什么?等一个Promise的异步返回,只要await声明的函数还没有返回数据,那么下面的程序是不会去执行的当这个Promise有了返回值,await的结果才会被取得,程序才会接着向下运行。

不过有人常说有了async/await的出现淘汰了Promise,这是错误的。两者是相辅相成的,缺一不可,你可以同时使用这两种语法,或者你更喜欢哪种语法就使用哪种语法

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

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

相关文章

MongoDB索引详解

概述 索引是一种用来快速查询数据的数据结构。BTree 就是一种常用的数据库索引数据结构,MongoDB 采用 BTree 做索引,索引创建 colletions 上。MongoDB 不使用索引的查询,先扫描所有的文档,再匹配符合条件的文档。使用索引的查询&…

web期末作业数字时钟,实时更新,音乐播放

文章目录 月球动态引导页加载引导页主页面主页面html需要完整代码私信我 月球动态引导页 加载引导页 主页面 主页面html <!DOCTYPE html> <html lang"zh-CN"><head><meta http-equiv"X-UA-Compatible" content"IEedge,chrome1&…

Socket closed 异常解决方案:如何解决 JMeter 压测中的问题

问题描述 JMeter 压测时会报 java.net.SocketException: Socket closed java.net.SocketException: Socket closed at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) at java.ne…

关于vite的glob坑

我先展示一段代码&#xff1a; /*** function 根据pages路径动态生成路由* param {Array} 基础路由*/ export default function (routes) {const modules import.meta.glob("../pages/**/page.js", { eager: true, import: "default" });const newRoutes…

centos用yum安装mysql详细教程

1 查询安装mysql的yum源,命令如下 ls /etc/yum.repos.d/ -l 界面如下图所示&#xff0c;未显示mysql的安装源 2 安装mysql相关的yum源,例如&#xff1a; 例如&#xff1a;rpm -ivh mysql57-community-release-el7.rpm 要注意 mysql的版本和系统的版本匹配 mysql57-communi…

北京大学漏洞报送证书

获取来源&#xff1a;edusrc&#xff08;教育漏洞报告平台&#xff09; url&#xff1a;教育漏洞报告平台(EDUSRC) 兑换价格&#xff1a;30金币 获取条件&#xff1a;北京大学任意中危或以上级别漏洞

使用定时器setInterval,在Moment.js 时间格式化插件基础上完成当前时间持续动态变化

1、引入插件 npm install moment --save 2、js配置&#xff1a;当前需要使用的文件中直接引入 import moment from moment; 3、代码实现&#xff1a;定义一个变量进行回显 3.1、dom部分 <span> {{ timeData }} </span> 3.2、js代码 <script> import mo…

MongoDB聚合操作

聚合操作概述 聚合操作允许用户处理多个文档并返回计算结果。聚合操作组值来自多个文档&#xff0c;可以对分组数据执行各种操作以返回单个结果。聚合操作包含三类&#xff1a;单一作用聚合、聚合管道、MapReduce。 单一作用聚合 提供了对常见聚合过程的简单访问&#xff0c…

shell编程-分支语句和循环结构

流控制: •在一个shell脚本中的命令执行顺序称作脚本的流。大多数脚本会根据一个或多个条件来改变它们的流。 •流控制命令:能让脚本的流根据条件而改变的命令称为条件流控制命令 •exit语句:退出程序的执行&#xff0c;并返回一个返回码&#xff0c;返回码为0正常退出&#…

智慧校园全空间三维电子沙盘系统

一、概述 易图讯科技&#xff08;www.3dgis.top&#xff09;采用大数据、云计算、虚拟现实、物联网、AI等先进技术&#xff0c;自主可控高性能WebGIS可视化引擎&#xff0c;支持多用户客户端通过网络请求访问服务器地图和专题数据&#xff0c;提供地理信息数据、专题数据的并发…

真空引水罐 虹吸抽水机 负压虹吸罐 农业灌溉工作原理动画介绍

​ 1&#xff1a;真空引水罐虹吸抽水机虹吸罐介绍 真空引水罐是一种水泵吸水设备&#xff0c;也被称为真空罐、吸水罐或自动引水装置。它是一个密封的罐体&#xff0c;被串联在泵前的吸水管上&#xff0c;能够使水泵的吸水口从负压吸水变为正压吸水。使用真空引水罐可以节省真…

探索LinkedIn:使用TypeScript和jsdom库的高级内容下载器

概述 LinkedIn是一个专业的社交网络平台&#xff0c;拥有超过7亿的用户和数以亿计的职位、公司和教育机构的信息。对于数据分析师、市场营销人员、招聘人员和其他对LinkedIn数据感兴趣的人来说&#xff0c;能够从LinkedIn上获取和分析这些信息是非常有价值的。 因此&#xff0…