网络请求 - 异步编程详解

一、概述

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

  • 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.mzph.cn/news/602284.shtml

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

相关文章

MyBatis - 批量更新(update foreach)报错

在使用mybatis执行批量更新(update foreach)数据的时候报错如下: org.springframework.jdbc.BadSqlGrammarException: ### Error updating database. Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; c…

基于web3+solidity的众筹项目

基本配置:node、npm、yarn,安装ganache,chrome,chrome安装插件MetaMask, 主要功能:目的是实现一个简单的众筹平台,允许用户发起筹款项目、捐款、提出使用资金请求以及证明人证明。 部分合约&…

echarts 仪表盘进度条 相关配置

option {series: [{type: gauge,min: 0,//最大值max: 100, //最小值startAngle: 200,//仪表盘起始角度。圆心 正右手侧为0度,正上方为90度,正左手侧为180度。endAngle: -20,//仪表盘结束角度splitNumber: 100, //仪表盘刻度的分割段数itemStyle: {color…

深度学习|4.1 深L层神经网络 4.2 深层网络的正向传播

4.1 深L层神经网络 对于某些问题来说,深层神经网络相对于浅层神经网络解决该问题的效果会较好。所以问题就变成了神经网络层数的设置。 其中 n [ i ] n^{[i]} n[i]表示第i层神经节点的个数, w [ l ] w^{[l]} w[l]代表计算第l层所采用的权重系数&#xff…

day07 四数相加Ⅱ 赎金信 三数之和 四数之和

题目1:454 四数相加Ⅱ 题目链接:454 四数相加Ⅱ 题意 4个整数数组nums1, nums2, nums3, nums4的长度均为n,有多少个元组(i,j,k,l)使得 nums[…

Python如何生成个性二维码

Python-生成个性二维码 一、问题描述 通过调用MyQR模块来实现生成个人所需二维码。 安装: pip install myqr 二、代码实现 1.普通二维码 from MyQR import myqr # 普通二维码 myqr.run(wordshttp://www.csdn.net/mayi0312,save_nameqrcode.png ) 效果图&#…

@JsonFormat与@DateTimeFormat

JsonFormat注解很好的解决了后端传给前端的格式,我们通过使用 JsonFormat可以很好的解决:后台到前台时间格式保持一致的问题 其次,另一个问题是,我们在使用WEB服务的时,可 能会需要用到,传入时间给后台&am…

buuctf-Misc 题目解答分解109-111

109.[CFI-CTF 2018]webLogon capture 流量包分析, wireshark 打开 就这几个数据包,追踪http 进行url 解码 URL网址解码器 - 在线网址解码 得到flag CFI{1ns3cur3_l0g0n} 110.[GKCTF 2021]excel 骚操作 下载 excel 文件 ,打开 发现点击其他地…

计算机Java项目|基于Springboot实现患者管理系统

作者主页:编程指南针 作者简介:Java领域优质创作者、CSDN博客专家 、掘金特邀作者、多年架构师设计经验、腾讯课堂常驻讲师 主要内容:Java项目、毕业设计、简历模板、学习资料、面试题库、技术互助 文末获取源码 项目编号:KS-032…

CanFestival结合Android来完成canopen通信

1.准备开发环境 安装Android Studio和NDK后,需要在Android Studio中创建一个新的NDK项目,并且在项目目录下创建一个jni目录来放置NDK代码。 配置CAN总线接口硬件需要根据具体的硬件要求进行,常见的方法包括使用串口或USB连接CAN总线接口&…

PyTorch Tutorial

本文作为博客“Transformer - Attention is all you need 论文阅读”的补充内容,阅读的内容来自于 https://pytorch.org/tutorials/intermediate/char_rnn_classification_tutorial.html#recommended-preparation 建议的准备流程。 Deep Learning with PyTorch: …

网络知识-以太网技术的发展及网络设备

目 录 一、背景介绍 (一)网络技术的时代 (二)以太网技术脱颖而出 二、以太网的工作原理 (一)、载波侦听多路访问(CSMA/CD) 1、数据发送流程 2、发送过程解析 3、…

WeNet语音识别+Qwen-72B-Chat Bot+Sambert-Hifigan语音合成

WeNet语音识别Qwen-72B-Chat Bot👾Sambert-Hifigan语音合成 简介 利用 WeNet 进行语音识别,使用户能够通过语音输入与系统进行交互。接着,Qwen-72B-Chat Bot作为聊天机器人接收用户的语音输入或文本输入,提供响应并与用户进行对话…

RPC基础知识总结

RPC 是什么? RPC(Remote Procedure Call) 即远程过程调用,通过名字我们就能看出 RPC 关注的是远程调用而非本地调用。 为什么要 RPC ? 因为,两个不同的服务器上的服务提供的方法不在一个内存空间,所以&am…

软件测试/测试开发丨Vuetify框架的使用

介绍 Vuetify 是一个基于 Vue.js 精心打造 UI 组件库,整套 UI 设计为 Material 风格。能够让没有任何设计技能的开发者创造出时尚的 Material 风格界面。 为什么要使用Vuetify框架 所有组件遵从 Material Design 设计规范,UI 体验非常优秀&#xff0c…

zookeeper经典应用场景之分布式锁

1. 什么是分布式锁 在单体的应用开发场景中涉及并发同步的时候,大家往往采用Synchronized(同步)或者其他同一个JVM内Lock机制来解决多线程间的同步问题。在分布式集群工作的开发场景中,就需要一种更加高级的锁机制来处理跨机器的进…

MiniTab的宏基础知识

什么是宏? 宏是包含一系列 Minitab 会话命令的文本文件。可以使用宏自动执行重复性任务(例如,生成月度报表)或扩展 Minitab 的功能(例如,计算特殊检验统计量)。 Minitab 提供以下类型的宏&…

MongoDB索引详解

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

Spring IOC的四种手动注入方法

手动注入 1.Set方法注入-五种类型的注入1.1 业务对象JavaBean第一步:创建dao包下的UserDao类第二步:属性字段提供set⽅法第三步:配置⽂件的bean标签设置property标签第四步:测试 1.2 常用对象String(日期类型&#xff…

每日一题——LeetCode1089.复写0

方法一 splice: 通过数组的slice方法,碰到 0就在后面加一个0,最后截取原数组的长度,舍弃后面部分。 但这样做是违反了题目的要求,不要在超过该数组长度的位置写入元素。 var duplicateZeros function(arr) {var le…