当前位置: 首页 > news >正文

JS之同步异步promise、async、await

promise异步操作

Promise是异步编程的一种解决方案

JavaScript异步与同步解析

学习promise前我们先来了解下什么是异步?

基本概念:

  • 消息队列中的任务分为宏任务与微任务;
  • 调用栈也可以称为主线程

首先我们要知道js是单线程语言,也就是说,它并不能像JAVA语言那样,多个线程并发执行。

单线程:

  • JavaScript就是一个单线程的语言
  • 为什么js是单线程?如果一个线程在一个节点中添加内容,另一个线程要删除这个节点。所以为了不必要的麻烦,js就是一门单线程语言。

先讲下什么是同步。同步指的是代码一行一行依次执行,下面的代码必须等待上面代码的执行完成。当遇到一些耗时比较长的任务时,比如网络请求就容易发生阻塞,必须等数据请求过来后才能执行后面的操作。

image-20231012091327982

那么这里异步执行是在请求数据的同时还能执行后面的任务。异步是非阻塞的,异步逻辑与主逻辑相互独立,主逻辑不需要等待异步逻辑完成,而是可以立刻继续下去

image-20231012091440179

JS的异步执行分析:

  • 拿现实生活来举例,比如一个人在家(将一个人比作单线程),你既要煮饭又要炒菜。
  • 这里我们把煮饭算作一个异步的任务,因为煮饭是一个比较耗时的任务(一般像比较耗时或不确定执行时间的任务,比如定时器,网络请求,事件执行 都是异步执行),其次你没炒完菜是不会去吃饭的(也就是主线程任务没有完成,是不会执行异步任务的)。
  • 那么你可以怎么做呢?你可以把煮饭的任务交给电饭煲处理。
  • 先把米放入电饭煲交给了电饭煲处理,再去炒菜,炒完菜再去把煮好的饭取出来。
  • 将饭交给电饭煲处理相当于开启了一个异步的任务,电饭煲就是处理这个异步任务的模块。饭煮好了会自动跳转,这就相当于异步任务被对应的模块解析好了会自动放入消息队列,等待事件循环调入主线程执行(前提是主线程任务全部执行完毕)
  • 主线程任务执行完成,会通过不断的循环消息队列,来执行其中的任务
  • 也就是你把炒菜完了,你就会不断的观察饭是否跳转(也就是循环消息队列看是否有任务),如果有就把饭装到碗里开始吃饭,此时任务就全部完成。
  • 但是干活的始终还是一个人,这就是单线程的异步执行过程。
    20210610125743317
console.log("遇到煮饭任务,将饭放入电饭煲");
//使用setTimeout模拟煮饭
setTimeout(()=>{console.log("饭已经煮熟,等待饭被取出");
},0);
console.log("开始炒菜任务");
  • 你以为的执行顺序:“遇到煮饭任务,将饭放入电饭煲 ” -> “饭已经煮熟,等待饭被取出 -> ”开始炒菜任务“
  • 但是你想想这样符合逻辑吗,你会等饭熟练才开始炒菜吗?
  • 最终执行顺序:“遇到煮饭任务,将饭放入电饭煲 ” -> “开始炒菜任务” -> “饭已经煮熟,等待饭被取出”
  • 显然js都知道你认为的执行顺序是不符合逻辑的。这里setTimeout就是一个异步任务,其中的箭头函数就是异步完成后回调的函数。

解释疑惑:
JavaScript既然是单线程语言,那么为什么同时可以执行多个任务(同时煮饭炒菜)?

  • 你可能会想这不是废话吗,煮饭交给电饭煲了啊。

  • 确实没错,煮饭任务交给电饭煲了,那么在JS中是谁去处理这些异步的任务呢?

    • 前面异步任务分析有说到,异步任务会被对应模块解析(饭被电饭煲模块解析)。

    • 那么这就和宿主有关系了,js一般都是运行在游览器上(当然有node.js),也就是寄生在游览器上,那么宿主就是游览器。所以是宿主提供的模块去处理这些异步任务,使得JS可以实现与其他语言类似的多线程操作。

补充异步任务执行顺序:

  • 而常见的promise,async,await 执行放入的是微任务队列中,主线程的代码执行完后,会优先循环微任务队列的代码,再是宏任务队列。
  • 主线程 > 微任务 > 宏任务
  • 注意!!宏任务队列与微任务队列的任务都是谁先进入队列谁先执行。

网络异步请求

<!DOCTYPE html>
<html><head></head><body></body>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script>console.log(1)$.ajax({type: "post",url: "https://tenapi.cn/v2/yiyan",success: function (response) {console.log(response)}});console.log(2)
</script></html>

image-20231012183016051

异步任务的影响

所以从上可以看出异步的执行是依赖于回调函数,那么在进行异步操作时回调函数会带来什么影响呢?那就是回调地狱。

回调地狱指的是:回调函数嵌套回调函数,形成的多层嵌套。

例子:查询三次网络请求,请求成功一次才会发起下一个请求

<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script>$.ajax({type: "post",url: "https://tenapi.cn/v2/yiyan",success(data) {console.log("第一次成功查询信息:", data);$.ajax({type: "post",url: "https://tenapi.cn/v2/yiyan",success(data) {console.log("第二次成功查询信息", data);$.ajax({type: "post",url: "https://tenapi.cn/v2/yiyan",success(data) {console.log("第三次成功查询信息", data);},error(error) {console.log("第三次成功信息出现异常了:" + error);}});},error(error) {console.log("第二次成功信息出现异常了:" + error);}});},error(error) {console.log("第一次成功信息出现异常了:" + error);}});</script>

image-20231012185118570

Promise的用法

异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理且更强大

实例化Promise对象

var promise = new Promise(传一个函数);
var promise = new Promise(function (resolve, reject) {if (/* 异步操作成功 */) {resolve(value);} else {reject(error);}
});
  • shi

三个状态

有三个状态:

  • pending [待定] 初始状态
  • fulfilled [实现] 操作成功
  • rejected [拒绝] 操作失败
var promise = new Promise(function (resolve, reject) {if (false) {resolve('success');} else {reject('fail');}});promise.then(res => {console.log(res) // 成功 resolve('success')}).catch(err => {console.log(err) // 失败 reject('fail');});

image-20231012190329560

当promise状态发生改变,就会触发then()里的响应函数处理后续步骤

状态改变,只有两种可能:

  • 从pending变为fulfilled
  • 从pending变为rejected

相关API

Promise.all

Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值

<script>//Promise.all let p1 = new Promise((resolve, reject) => {resolve('成功了')})let p2 = new Promise((resolve, reject) => {resolve('success')})let p3 = Promise.reject('失败')Promise.all([p1, p2]).then((result) => {console.log(result) //['成功了', 'success']}).catch((error) => {console.log(error)})Promise.all([p1, p3, p2]).then((result) => {console.log(result)}).catch((error) => {console.log(error) // 失败了,打出 '失败'})
</script>

image-20231012202520115

Promise.race

顾名思义, Promse.race就是赛跑的意思,意思就是说, Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态

<script>let p1 = new Promise((resolve, reject) => {setTimeout(() => {resolve('success')}, 1000)})let p2 = new Promise((resolve, reject) => {setTimeout(() => {reject('failed')}, 500)})Promise.race([p1, p2]).then((result) => {console.log(result)}).catch((error) => {console.log(error) // 打开的是 'failed'})
</script>

image-20231012202807074

使用Promise解决回调地狱

如上代码就是产生了回调地狱,当代码过多会非常复杂。如下就是使用一种优雅的方式(promise)来解决如上的问题

  • 解决刚刚那个发送三次请求案例
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script>//使用Promise解决回调地狱function post(url,n) { //自己定义一个方法整合一下return new Promise((resolve, reject) => {$.ajax({url: url,success: function (data) {resolve(data);},error: function (err) {reject(`${n}次调用失败`+err)}})});}post("https://tenapi.cn/v2/yiyan",1).then((data) => {console.log("第一次成功查询信息:", data)return post("https://tenapi.cn/v2/yiyan",2);}).then((data) => {console.log("第二次成功查询信息:", data)return post("https://tenapi.cn/v2/yiyan",3);}).then((data) => {console.log("第三次成功查询信息", data)}).catch((err) => { //失败的话catchconsole.log( err)});
</script>
  • 这样代码就显的非常清楚,不想之前那样非常难懂

image-20231012205206442

总结

Promis就是对异步操作进行封装,其中的思想就是不希望你在回调函数中处理需要执行的代码,而是把回调执行的代码放入对应的区域也就是then()或catch()方法中处理,然后通过resolve()或reject()来调用。将代码分离后做的时链式的调用,你可以这样理解一个then或一个catch就是一个链条的连接点。一般有异步操作我们都要使用promise对异步操作进行封装,养成良好的习惯。

JS的同步执行解析:

  • 代码由上至下依次执行。前面任务在执行,后面代码必须排队等待。
  • 就如上面的例子如果不做异步处理,让任务同步执行就会一直卡在做饭的地方,等饭煮好了才能去炒菜。

Async / await

也是用来处理异步的,其实是Generator 函数的改进,背后原理就是promise

Async

<script>
async function f1() {return "abc";}
console.log(f1())
</script>

image-20231012214027122

// async
async function f1() {return "abc";// 自动包装成promise对象// 与下面两种等价// return Promise.resolve('abc');// return new Promise((resolve) => { resolve('abc') });
}
f1().then((data)=>{console.log("执行了异步",data)
})

image-20231012214200026

await

function f4() {setTimeout(() => {console.log("222")}, 3000)console.log("333")
}
function f5() {console.log("111")f4(); console.log("444")
}
f5()

image-20231012214539743

async function f4() {await new Promise(function (resolve, reject) {setTimeout(() => {resolve()}, 3000)}).then((data)=>{console.log("222")})console.log("333")
}
function f5() {console.log("111")f4();console.log("444")
}
f5()

image-20231012221139473

async function f4() {await new Promise(function (resolve, reject) {setTimeout(() => {resolve()}, 3000)}).then((data)=>{console.log("222")})console.log("333")
}
async function f5() {console.log("111")await f4();console.log("444")
}
f5()

image-20231012221246600

异常处理

async function f3() {return Promise.reject('sss');// return Promise.resolve('abc')
}
async function f5() {try {var c = await f3().then((data)=>{ console.log(data)});} catch (e) {console.log(e)}//如果await 是reject,后面代码就不会执行,要加上try catch才会执行
}
f5()

image-20231012221614568

相关文章:

JS之同步异步promise、async、await

promise异步操作 Promise是异步编程的一种解决方案 JavaScript异步与同步解析 学习promise前我们先来了解下什么是异步&#xff1f; 基本概念&#xff1a; 消息队列中的任务分为宏任务与微任务;调用栈也可以称为主线程 首先我们要知道js是单线程语言&#xff0c;也就是说…...

【OpenCV • c++】自定义直方图 | 灰度直方图均衡 | 彩色直方图均衡

文章目录 一、什么是直方图二、自定义直方图三、灰度直方图均衡四、彩色直方图均衡一、什么是直方图 直方图广泛应用于很多计算机视觉处理当中。通过标记帧与帧之间显著的边缘和颜色的变化,可以检测视频中的场景变化。在每个兴趣点设置一个有相似特征的直方图所构成的“标签”…...

el-tree目录和el-table实现搜索定位高亮方法

需求&#xff1a;el-tree目录实现搜索查询el-table表格项&#xff0c;双击表格项根据yiZhuMLID||muLuID定位el-tree目录&#xff0c;并且高亮展示在可视化区域内&#xff0c;再重新根据el-tree目录的yiZhuMLID搜索刷新el-table表格&#xff0c;定位且高亮展示相对应的yiZhuMLID…...

linux常用指令

基础命令 cd&#xff1a;用于切换目录。例如&#xff0c;要从当前目录切换到/home/user目录&#xff0c;可以使用命令“cd /home/user”。ls&#xff1a;用于列出目录内容。例如&#xff0c;要列出当前目录的内容&#xff0c;可以使用命令“ls”。mkdir&#xff1a;用于创建目…...

C语言,指针的一些运算

若创建一个数组&#xff1a;int arr[10] 0; 用指针变量来储存数组首元素的地址&#xff1a;int* p arr,这里arr是数组名&#xff0c;表示首元素地址。 若p p 1或者p之后p本来指向数组首元素地址&#xff0c;就变成了指向第二个元素的地址&#xff0c;p n即指向第n 1个地…...

iPhone 如何强制重启

参考iPhone的官方使用手册 传送门 尤其当 iPhone 未响应&#xff0c;也无法将其关机再开机&#xff0c;此方法最有效&#xff1a; 按住调高音量按钮&#xff0c;然后快速松开。按住调低音量按钮&#xff0c;然后快速松开。按住侧边按钮。当 Apple 标志出现时&#xff0c;松开侧…...

数据结构--单链表操作

1.单链表的创建&#xff08;带头结点&#xff09; #include<stdlib.h> #define ElemType int typedef struct {//定义一个结点ElemType data;struct STU* next; }STU,*LinkList; bool InitList(LinkList& L) {L (STU*)malloc(sizeof(STU));//创建头结点if (L NUL…...

AlmaLinux (兼容centos)安装Geant4与ROOT

AlmaLinux 介绍 AlmaLinux OS 是一个开源、社区驱动的 Linux 操作系统&#xff0c;它填补了因 CentOS 稳定版本停止维护而留下的空白&#xff0c;同时更加强大。 安装 AlmaLinux 这个我用的是 windows 子系统进行安装 首先打开微软商店&#xff0c;然后搜索AlmaLinux&#…...

FPGA面试题(2)

一.同步复位和异步复位 同步复位&#xff1a;当clk有效时&#xff0c;复位才有效。优点&#xff1a;有利于时序分析&#xff0c;防止毛刺现象出现。缺点&#xff1a;复位信号必须大于时钟周期&#xff0c;大部分逻辑器件中D触发器都只有异步复位端口&#xff0c;需要在寄存器数…...

【C++ Primer Plus学习记录】指针——使用new来创建动态数组

目录 1.使用new创建动态数组 2.使用动态数组&#xff08;如何使用指针访问数组元素&#xff09; 如果程序只需要一个值&#xff0c;则可能会声明一个简单变量&#xff0c;因为对于管理一个小型数据对象来说&#xff0c;这样做比使用new和指针更简单。通常&#xff0c;对于大型…...

移动app广告变现,对接广告联盟还是选择第三方聚合广告平台?

作为互联网广告的载体&#xff0c;APP天生就比线下传统广告位更具优势&#xff0c;不受地域限制可以辐射到地球上的每一个角落&#xff0c;可以让广告获得更广的覆盖面。通过丰富的广告形式&#xff0c;精准的目标用户画像&#xff0c;也可以更好地实现品牌广告或效果广告的投放…...

ARM 按键控制 LED灯,蜂鸣器,风扇

main.c: #include "uart.h" #include "key_it.h" int main() {all_led_init();uart4_init();//串口初始化//中断初始化key_it_config();key3_it_config();buzzer_init();fan_init();while(1){//保证主程序不结束}return 0; }src/key_it.c: #include"…...

VirtualBox Ubuntu扩展虚拟机磁盘空间

关于Orical VM VirtualBox虚拟机安装了ubuntu linux系统&#xff0c;由于需要&#xff0c;磁盘空间不足&#xff0c;需要扩展磁盘空间&#xff0c;最终找到了一个非常简单的方法&#xff0c;上干货。 1、关闭虚拟机 2、运用VBoxManage命令扩展vdi文件的空间 打开windows的命…...

C#开发的OpenRA游戏之电力系统之二

C#开发的OpenRA游戏之电力系统之二 继续前面的电力系统分析,在OpenRA游戏里,每一个建筑物都会有一个电力描述字段,说明这个建筑物是消耗电力,还是产生电力的。如果这个建筑物是产生电力的,那么这个字段就会是正值,如果这个建筑物是消耗电力的,就会是负值。因此所有电厂…...

Java架构师基础框架设计

目录 1 导学2 理解软件框架3 框架设计里面的框架和设计模式的关系4 基础框架中常见的基本功能4.1 事务处理4.2 微服务网络调用4.3 缓存实现4.4 分布式id4.5 任务调度4.6 工作流5 基础框架的几种基本的使用方式5.1 继承方式5.2 注解或注解加AOP的方式5.3 将基础框架的功能直接当…...

tortoise创建本地仓库

1.安装git和tortoise 推荐 TortoiseGit的安装与配置方法 以及 Git TortoiseGit 配置步骤以及本地版本管理 这里记录一下我遇到的问题 1.右键没有创建本地版本库 2 .创建了但是克隆不了 后续专有 一般选专有网络 注意自行谨慎选择 自行负责...

【FreeRTOS】【STM32】03 FreeRTOSConfig.h头文件简介与修改

基于[野火]《FreeRTOS%20内核实现与应用开发实战—基于STM32》.pdf FreeRTOSConfig.h头文件是FreeRTOS各项功能的打开与关闭 FreeRTOSConfig.h头文件简介 之前也说过了&#xff0c;FreeRTOSConfig.h文件可以添加在工程中任意文件夹&#xff0c;只需要在路径中添加好了就行。…...

VScode商店无法访问

下面的方法也许对你没用&#xff0c;也许也有用&#xff0c;但是尝试一下不会有任何副作用。 步骤一&#xff1a; 步骤二&#xff1a;在Proxy代理设置中复制输入 http://127.0.0.1:8080 步骤三&#xff1a;关闭软件&#xff0c;再打开VScode&#xff0c;把http://127.0.0.1:8…...

【UnityUGUI】复合控件详解,你还记得多少

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;UI_…...

ubuntu下使用gcc编译c程序: “error: stray ‘\357’ in program“

现象&#xff1a; ubuntu下使用gcc编译c程序: “error: stray ‘\357’ in program“ 尝试查找原因&#xff1a;打开从windos直接粘贴c程序到ubuntu的c代码&#xff0c;发现多了 <200b>&#xff1a; 方案&#xff1a;尝试在vim编辑器删除&#xff0c;多出来的字符后编译…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

【Linux】shell脚本忽略错误继续执行

在 shell 脚本中&#xff0c;可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行&#xff0c;可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令&#xff0c;并忽略错误 rm somefile…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:

一、属性动画概述NETX 作用&#xff1a;实现组件通用属性的渐变过渡效果&#xff0c;提升用户体验。支持属性&#xff1a;width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项&#xff1a; 布局类属性&#xff08;如宽高&#xff09;变化时&#…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…...

ArcGIS Pro制作水平横向图例+多级标注

今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作&#xff1a;ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等&#xff08;ArcGIS出图图例8大技巧&#xff09;&#xff0c;那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

基于 TAPD 进行项目管理

起因 自己写了个小工具&#xff0c;仓库用的Github。之前在用markdown进行需求管理&#xff0c;现在随着功能的增加&#xff0c;感觉有点难以管理了&#xff0c;所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD&#xff0c;需要提供一个企业名新建一个项目&#…...

人机融合智能 | “人智交互”跨学科新领域

本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...