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

JS 异步接口调用介绍

JS 异步接口调用介绍

Js 单线程模型

JavaScript 语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。这样设计的方案主要源于其语言特性,因为 JavaScript 是浏览器脚本语言,它可以操纵 DOM ,可以渲染动画,可以与用户进行互动,如果是多线程的话,执行顺序无法预知,而且操作以哪个线程为准也是个难题。

 

所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变。

HTML5 时代,浏览器为了充分发挥 CPU 性能优势,允许 JavaScript 创建多个线程,但是即使能额外创建线程,这些子线程仍然是受到主线程控制,而且不得操作 DOM,类似于开辟一个线程来运算复杂性任务,运算好了通知主线程运算完毕,结果给你,这类似于异步的处理方式,所以本质上并没有改变 JavaScript 单线程的本质。

任务队列

所有任务可以分成两种,一种是 同步任务(synchronous),另一种是 异步任务(asynchronous)

同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务。

所以,当在执行过程中遇到一些类似于 setTimeout 等异步操作的时候,会交给浏览器的其他模块进行处理,当到达 setTimeout 指定的延时执行的时间之后,回调函数会放入到任务队列之中。

当然,一般不同的异步任务的回调函数会放入不同的任务队列之中。等到调用栈中所有任务执行完毕之后,接着去执行任务队列之中的回调函数

JavaScript
 setTimeout(() => {
    console.log('setTimeout')
  }, 22)//定时22ms,后执行setTimeout
  for (let i = 0; i++ < 2;) {
    i === 1 && console.log('1')
  }
  setTimeout(() => {
    console.log('set2')
  }, 20)//定时20ms 后执行console.log('set2')
  //下边循环时间假定是50ms
  for (let i = 0; i++ < 100000000;) {
    i === 99999999 && console.log('2')
  }
 

大家可以猜测下它的输出内容?

输出结果是1,2,set2, setTimeOut

那你可能会好奇为什么结果是这样的呢,为了讲清楚这个问题答案,我们先要搞清楚两个任务,一个是macro-task(宏任务),一个micro-task(微任务)

macro-task(宏任务)

大概包括:script(整体代码), setTimeout, setInterval, setImmediate(NodeJs), I/O, UI rendering。

micro-task(微任务)

大概包括: process.nextTick(NodeJs), Promise,  来自不同任务源的任务会进入到不同的任务队列。
 

执行顺序是一开始先

 

主循环下来,先把微队列任务执行完成,在执行宏队列的一个任务,这个宏任务完成在去执行微队列,就这样依次循环执行

有了上边的基础,我们接下来在看下下边代码执行过程

JavaScript
setTimeout(() => {
  console.log(4)
}, 0);
//Promise构造方法先执行
new Promise((resolve) =>{
  console.log(1);
  for (var i = 0; i < 10000000; i++) {
    i === 9999999 && resolve();
  }
  console.log(2);
}).then(() => {
  console.log(5);
});
console.log(3);
 

Promise的构造方法的第一个方法会立即执行的,后边then会放到微任务队列里办

第一遍执行完成后会输出

1 2 3

此时的宏队列与微队列是

宏队列

微队列

setTimeout

then

一开始js脚本是执行的宏队列,这里轮到了微队列,会先执行Promise里边的then,此时微队列空了,接着执行宏队列,后续输出的应该是

5 4

最终输出的是

1 2 3 5 4

在看下下边这个复杂的

JavaScript
<script>
  setTimeout(() => {
    console.log(4)
  }, 0);
  new Promise((resolve) => {
    console.log(1);
    for (var i = 0; i < 10000000; i++) {
      i === 9999999 && resolve();
    }
    console.log(2);
  }).then(() => {
    console.log(5);
  });
  console.log(3);
</script>
<script>
  console.log(6)
  new Promise((resolve) => {
    resolve()
  }).then(() => {
    console.log(7);
  });
</script>

首先我们可以看到script有2个,我们暂且叫它script1,

宏队列

微队列

script1

script2

宏队列开始执行script1 的脚本后,Promise构造方法会立即执行,所以会先打印出来

1 2 3

此时对列为

宏队列

微队列

script2

then5

setTimeout4

script1 宏任务执行完成后,接着要把微队列任务都要执行完成,接着执行5

1 2 3 5

宏队列

微队列

script2

setTimeout4

执行script2

1 2 3 5 6

宏队列

微队列

setTimeout4

then7

接着执行微队列then

1 2 3 5 6 7

就剩最后一个宏任务setTimeout4了

1 2 3 5 6 7 4

如果现在大家搞清楚了,js 的异步多少会有一些了解

接下来介绍下async 与 await

async

async 函数是使用async关键字声明的函数。async 函数是 AsyncFunction 构造函数的实例,并且其中允许使用 await 关键字。asyncawait 关键字让我们可以用一种更简洁的方式写出基于 Promise 的异步行为,而无需刻意地链式调用 promise

JavaScript
function resolveAfter2Seconds() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('resolved');
    }, 2000);
  });
}

async function asyncCall() {
  console.log('calling');
  const result = await resolveAfter2Seconds();
  console.log(result);
  // Expected output: "resolved"
}

asyncCall();
 

我们来分析下这个代码

宏队列

微队列

asyncCall()

执行asyncCall()

输出calling

宏队列

微队列

resolveAfter2Seconds()

宏队列

微队列

2s以后setTimeout

宏队列

微队列

console.log(result)

最终输出结果

Calling

#2秒以后输出

resolve

Promise

Promise 对象用于表示一个异步操作的最终完成(或失败)及其结果值。

一个 Promise 必然处于以下几种状态之一:

  • 待定(pending:初始状态,既没有被兑现,也没有被拒绝。
  • 已兑现(fulfilled:意味着操作成功完成。
  • 已拒绝(rejected:意味着操作失败。

Promise.reject(reason)

返回一个状态为已拒绝的 Promise 对象,并将给定的失败信息传递给对应的处理函数。

Promise.resolve(value)

返回一个状态由给定 value 决定的 Promise 对象。如果该值是 thenable(即,带有 then 方法的对象),返回的 Promise 对象的最终状态由 then 方法执行结果决定;否则,返回的 Promise 对象状态为已兑现,并且将该 value 传递给对应的 then 方法。

await

await 操作符用于等待一个 Promise 兑现并获取它兑现之后的值。它只能在异步函数或者模块顶层中使用。

当函数执行到 await 时,被等待的表达式会立即执行,所有依赖该表达式的值的代码会被暂停,并推送进微任务队列(microtask queue)。然后主线程被释放出来,用于事件循环中的下一个任务。即使等待的值是已经敲定的 promise 或不是 promise,也会发生这种情况。例如,考虑以下代码:

JavaScript
async function foo(name) {
  console.log(name, "start");
  await console.log(name, "middle");
  console.log(name, "end");
}

foo("First");
foo("Second");

// First start
// First middle
// Second start
// Second middle
// First end
// Second end

可以转化成

JavaScript
function foo(name) {
  return new Promise((resolve) => {
    console.log(name, "start");
    resolve(console.log(name, "middle"));
  }).then(() => {
    console.log(name, "end");
  });
}

可以看下加黄色的字体,await可以转成 Promise.then,会被放到微任务队列

JavaScript
let i = 0;

queueMicrotask(function test() {
  i++;
  console.log("microtask", i);
  if (i < 3) {
    queueMicrotask(test);
  }
});

(async () => {
  console.log("async function start");
  for (let i = 1; i < 3; i++) {
    await null;
    console.log("async function resume", i);
  }
  await null;
  console.log("async function end");
})();

queueMicrotask(() => {
  console.log("queueMicrotask() after calling async function");
});

console.log("script sync part end");
//async function start
//script sync part end
//microtask 1
//async function resume 1
//queueMicrotask() after calling async function
//microtask 2
//sync function resume 2
//microtask 3
//async function end
 

相关文章:

JS 异步接口调用介绍

JS 异步接口调用介绍 Js 单线程模型 JavaScript 语言的一大特点就是单线程&#xff0c;也就是说&#xff0c;同一个时间只能做一件事。这样设计的方案主要源于其语言特性&#xff0c;因为 JavaScript 是浏览器脚本语言&#xff0c;它可以操纵 DOM &#xff0c;可以渲染动画&a…...

5.深入理解HttpSecurity的设计

深入理解HttpSecurity的设计 一、HttpSecurity的应用 在前章节的介绍中我们讲解了基于配置文件的使用方式&#xff0c;也就是如下的使用。 也就是在配置文件中通过 security:http 等标签来定义了认证需要的相关信息&#xff0c;但是在SpringBoot项目中&#xff0c;我们慢慢脱离…...

opencv-python numpy常见的api接口汇总(持续更新)

前言 最近写代码总是提笔忘api&#xff0c;因为图像处理代码写的比较多&#xff0c;所以想着把一些常用的opencv的api&#xff0c;包括numpy的api做一个记录&#xff0c;后面再忘记的时候&#xff0c;就不用去google挨个搜索了&#xff0c;只需要在自己的博客中一查就全知道了…...

概率论小课堂:伯努利实验(正确理解随机性,理解现实概率和理想概率的偏差)

文章目录 引言I 伯努利试验1.1 伯努利分布(二项式分布)1.2 数学期望值(简称期望值)1.3 平方差(简称方差)1.4 标准差1.5 小结引言 假设买彩票中奖的概率是一百万分之一,如果要想确保成功一次,要买260万次彩票。你即使中一回大奖,花的钱要远比获得的多得多。 很多人喜…...

加密功能实现

文章目录1. 前言2. 密码加密1. 前言 本文 主要实现 对密码进行加密 &#xff0c;因为 使用 md5 容易被穷举 (彩虹表) 而破解 &#xff0c;使用 spring security 框架又太大了 (杀鸡用牛刀) 。   所以本文 就自己实现一个密码加密 . 2. 密码加密 这里我们通过 加盐是方式 来 对…...

大数据项目实战之数据仓库:用户行为采集平台——第1章 数据仓库概念

第1章 数据仓库概念 数据仓库&#xff08;Data Warehouse&#xff09;&#xff0c;是为企业制定决策&#xff0c;提供数据支持的。可以帮助企业改进业务流程、提高产品质量等。 数据仓库的输入数据通常包括&#xff1a;业务数据、用户行为数据和爬虫数据等 业务数据&#xf…...

NTP对时服务器(NTP电子时钟)在生物制药业应用

NTP对时服务器&#xff08;NTP电子时钟&#xff09;在生物制药业应用 NTP对时服务器&#xff08;NTP电子时钟&#xff09;在生物制药业应用 8.1 系统概述 时钟系统为生物制药厂网络控制中心调度员、车场值班员及各部门工作人员提供统一的标准时间信息&#xff0c;也为本工程其它…...

JPA 之 QueryDSL-JPA 使用指南

Querydsl-JPA 框架&#xff08;推荐&#xff09; 官网&#xff1a;传送门 参考&#xff1a; JPA整合Querydsl入门篇SpringBoot环境下QueryDSL-JPA的入门及进阶 概述及依赖、插件、生成查询实体 1.Querydsl支持代码自动完成&#xff0c;因为是纯Java API编写查询&#xff0…...

如何找回回收站删除的视频?这三种方法可以试试

在使用电脑过程中&#xff0c;我们可能会误删重要的文件&#xff0c;特别是影音文件。在这样的情况下&#xff0c;我们可以从计算机的回收站中找回已经被删除的视频。但是有时候&#xff0c;我们可能会不小心清空回收站&#xff0c;这时候就需要一些技巧来恢复回收站删除的视频…...

FPGA_边沿监测理解

一、简易频率计设计中为什么一定要获取下降沿?gate_a:实际闸门信号gate_a_stand:将实际闸门信号打一拍之后的信号gate_a_fall_s:下降沿标志信号cnt_clk_stand: Y值&#xff0c;即在实际闸门信号下&#xff0c;标准时钟信号的周期个数cnt_clk_stand_reg:保存Y值的寄存器核心问题…...

41 42Ping-Pong操作

提高电路吞吐率的结构——Ping-Pong操作 1.Ping-Pong操作原理 作用&#xff1a;为了让两个不匹配的模块进行对接&#xff0c;并且在对接的过程中让这两个模块能够同时工作&#xff0c;提高数据处理的吞吐率&#xff08;也称throughput效能&#xff09; 常见的不匹配&#xff1…...

保护你的数据安全,了解网络安全法!

网络安全法是中国自2017年6月1日起实施的一项法律&#xff0c;旨在保障网络安全和信息安全&#xff0c;维护国家安全和社会稳定。网络安全法覆盖了众多方面&#xff0c;包括网络基础设施安全、网络运营安全、个人信息保护、网络安全监管等&#xff0c;具有重要的法律意义和社会…...

什么是CatGPT-使用效果如何-

个人使用效果&#xff0c;评分优&#xff0c;足以满足教学和填表。程序媛借助CatGPT&#xff08;ChatGPT更佳&#xff09;&#xff0c;基本上可以秒杀不用此类工具的程序猿&#xff08;男&#xff09;&#xff01;&#xff01;&#xff01;问&#xff1a;为什么使用AIGC能大幅度…...

【MySQL】第17章_触发器

第17章_触发器 在实际开发中&#xff0c;我们经常会遇到这样的情况&#xff1a;有 2 个或者多个相互关联的表&#xff0c;如商品信息和库存信息分别存放在 2 个不同的数据表中&#xff0c;我们在添加一条新商品记录的时候&#xff0c;为了保证数据的完整性&#xff0c;必须同时…...

【前端】一个更底层库-React基础知识点第2篇

目录属性状态PROPSPROP VALIDATIONSTATEFORMCONTROLLED COMPONENTSMIXINCOMPONENT APICOMPONENT LIFECYCLETOP API上一篇文章也是React基础知识点&#xff0c;了解到了React是什么&#xff1f;为什么要使用React&#xff1f;还知道了JSX概述&#xff0c;JSX嵌入变量&#xff0c…...

GIT基础常用命令-1

git基础常用命令-11.git简介及配置1.1 git简介1.2 git配置config1.2.1 查看配置git config1.2.2 配置设置1.2.3 获取帮助git help2 GIT基础常用命令2.1 获取镜像仓库2.1.1 git init2.1.2 git clone2.2 本地仓库常用命令2.2.1 git status2.2.2 git add2.2.3 git diff2.2.4 git c…...

02_qml_简介

qml介绍: QML是一种描述用户界面的声明式语言。它将用户界面分解成一些更小的元素,这些元素能够结合成一个组件。QML语言描述了用户界面元素的形状和行为。用户界面能够使用JavaScript来提供修饰,或者增加更加复杂的逻辑。从这个角度来看它遵循HTML-JavaScript模式,但QML是…...

小程序项目在hbuilder里面给它打包成app

小程序项目临时有些登录需求&#xff0c;需要把&#xff08;小程序某些功能通过条件编译让它显示到app上&#xff09;小程序打包成app的话就必须需要一个打包的证书&#xff0c;证书的话就要去重新生成&#xff0c;苹果电脑可以去自动生成证书&#xff0c;平时是用windows进行开…...

linux安装pycharm

linux安装pycharm1.下载相关软件包2. 安装步骤2.1 解压文件2.2 开启命令2.4 创建快捷方式官网链接 https://www.jetbrains.com/pycharm/download/#sectionlinux 1.下载相关软件包 找到自己下载的版本下载 2. 安装步骤 2.1 解压文件 进入压缩包路径 解压文件【我指定了解…...

seata1.5.2使用从零快速上手(提供代码与安装包)

1.软件准备&#xff1a; 1.1 seata1.5.2 官网下载&#xff1a;地址:http://seata.io/zh-cn/ server源码:https://github.com/seata/seata 百度云下载&#xff08;建议&#xff09;: 百度下载 链接&#xff1a;https://pan.baidu.com/s/1eilbSI0YdmupHYI7FroTsw 提取码&…...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用&#xff0c;操作系统&#xff1a;Ubuntu24.04&#xff0c;Neofj版本&#xff1a;2025.04.0。 Apt安装 Neofj可以进行官网安装&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

通过Wrangler CLI在worker中创建数据库和表

官方使用文档&#xff1a;Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后&#xff0c;会在本地和远程创建数据库&#xff1a; npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库&#xff1a; 现在&#xff0c;您的Cloudfla…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

ffmpeg(四):滤镜命令

FFmpeg 的滤镜命令是用于音视频处理中的强大工具&#xff0c;可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下&#xff1a; ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜&#xff1a; ffmpeg…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...

Swagger和OpenApi的前世今生

Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章&#xff0c;二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑&#xff1a; &#x1f504; 一、起源与初创期&#xff1a;Swagger的诞生&#xff08;2010-2014&#xff09; 核心…...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...