JS 异步接口调用介绍

news2024/10/6 12:36:01

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
 

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

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

相关文章

JavaScript RegExp 正则对象

文章目录JavaScript RegExp 正则对象RegExp 对象修饰符test()exec()方括号元字符量词RegExp 对象方法支持正则表达式的 String 对象的方法JavaScript RegExp 正则对象 RegExp&#xff1a;是正则表达式&#xff08;regular expression&#xff09;的简写。 RegExp 对象 正则表…

JPA 之 QueryDSL-JPA 使用指南

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

分布式架构之(Zookeeper原理)

Zookeeper是一个典型的分布式数据一致性的结局方案&#xff0c;分布式应用程序可以基于它实现注入数据发布、订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master选举、分布式锁和分布式队列等功能&#xff0c; Zookeeper可以保证如下分布式一致性特性&#xff1a; 顺…

MQ面试题

1、为什么使用消息队列&#xff1f; 其实就是问问你消息队列都有哪些使用场景&#xff0c;然后你项目里具体是什么场景&#xff0c;说说你在这个场景里用消息队列是什么&#xff1f; 面试官问你这个问题&#xff0c;期望的一个回答是说&#xff0c;你们公司有个什么业务场景&…

ADCS攻击之CVE-2022–26923

CSDN自动博客文章迁移漏洞简介该漏洞允许低权限用户在安装了 Active Directory 证书服务 (AD CS) 服务器角色的默认 Active Directory 环境中将权限提升到域管理员。在默认安装的ADCS里就启用了Machine模板。漏洞利用添加机器账户&#xff0c;并将该机器账户dnsHostName指向DC[…

Stable Diffusion Controlnet基础标志用法

ControlNet是一种图像生成AI技术,可以在保持输入图像结构不变的情况下,将输入图像转换为另一幅图像,例如可以使用ControlNet来生成通过使用简笔画等3D模型来实现具有指定人物姿势和构图的插图。 在这个过程中ControlNet可以从输入图像中提取轮廓、深度和分割等信息,并根据…

Redis和MySQL如何保持数据一致性?

在高并发的场景下&#xff0c;大量的请求直接访问MySQL很容易造成性能问题。所以&#xff0c;我们都会用Redis来做数据的缓存&#xff0c;削减对数据库的请求。但是&#xff0c;MySQL和Redis是两种不同的数据库&#xff0c;如何保证不同数据库之间数据的一致性就非常关键了。1.…

线程通信

线程通信 线程通信指的是多个线程通过相互牵制,相互调度,即线程间的相互作用 涉及的三个方法&#xff1a; .wait 一旦执行此方法,当前线程就进入到阻塞状态,并释放同步监视器 .notify 执行此方法,就会唤醒被wait的一个线程.如果有多个线程被wait,那么就会先唤醒优先级最高的…

HybridFusion: LiDAR和视觉交叉源点云融合

一、基本信息 研究方向&#xff1a; 大场景点云配准 HybridFusion: 它可以在户外大型场景中从不同视角记录交叉源密集点云。 团队链接&#xff1a;http://www.adv-ci.com 视频链接&#xff1a; https://www.bilibili.com/video/BV1vM41147yD/?spm_id_from333.337.sear…

蓝桥杯真题(解码)小白入!

本来看这个题感觉很简单&#xff0c;不就是Ascall值换来换去嘛&#xff0c;其实也真的这样&#xff0c;但是对于小白来说&#xff0c;ascall根本记不住 题目说了&#xff0c;每个数不会重复超过9次&#xff08;这见到那多了&#xff0c;不然根本不会写&#xff09; 其次如何实现…

2023年再不会Redis,就要被淘汰了

目录专栏导读一、同样是缓存&#xff0c;用map不行吗&#xff1f;二、Redis为什么是单线程的&#xff1f;三、Redis真的是单线程的吗&#xff1f;四、Redis优缺点1、优点2、缺点五、Redis常见业务场景六、Redis常见数据类型1、String2、List3、Hash4、Set5、Zset6、BitMap7、Bi…

Spring-Cloud-Gateway集成Nacos如何做负载均衡?

spring-cloud-alibaba的低版本 如果所用的SpringCloud和Nacos的版本信息如下&#xff1a; <spring-cloud.version>Hoxton.SR10</spring-cloud.version> <spring-cloud-alibaba.version>2.2.6.RELEASE</spring-cloud-alibaba.version>网关的依赖如下&…

VirtualBox虚拟机闪退后如何重新打开

电脑&#xff08;Mac系统&#xff09;由于某种问题自动重启了&#xff0c;重启后之前在用的VirtualBox&#xff08;虚拟机管理器&#xff09;能恢复运行&#xff0c;但VirtualBoxVM&#xff08;虚拟机终端&#xff09;进程已停止&#xff0c;点击管理器的「显示」也出现报错&am…

我国防疫数据报告,2022年广东花费711亿,北京人均支出第一

哈喽大家好&#xff0c;2023年已经过去一段时间了&#xff0c;随着防疫策略的调整&#xff0c;小伙伴们是不是开始到处旅行购物了呢&#xff1f;当然了&#xff0c;对于自身的健康情况小伙伴们还是要多多关注&#xff0c;不要松懈。随着春节过后有序复工复产&#xff0c;各地纷…

三叉神经痛是怎么回事?给予2个生活建议!

三叉神经痛被称为天下第一痛&#xff0c;三叉神经支配区域反复出现短暂性阵发性剧痛&#xff0c;发作时让人们备受折磨。近期早晚温差大和天气变化多端&#xff0c;可刺激肌肉和血管收缩&#xff0c;导致三叉神经异常放电&#xff0c;进而引起剧烈疼痛&#xff0c;诱发三叉神经…

ChatGPT强化学习大杀器——近端策略优化(PPO)

ChatGPT强化学习大杀器——近端策略优化&#xff08;PPO&#xff09; 近端策略优化&#xff08;Proximal Policy Optimization&#xff09;来自 Proximal Policy Optimization Algorithms&#xff08;Schulman et. al., 2017&#xff09;这篇论文&#xff0c;是当前最先进的强…

【学习笔记】深入理解JVM之垃圾回收机制

【学习笔记】深入理解JVM之垃圾回收机制 更多文章首发地址&#xff1a;地址 参考&#xff1a; 《深入理解JAVA虚拟机》第三版 第三章尚硅谷 第134 - 203 集参考文章&#xff1a;https://blog.csdn.net/qq_48435252/article/details/123697193 1、概念 &#x1f33b; 首先我们…

Mock.js介绍及使用总结

1 什么是Mock.js Mock.js用于生成随机的模拟数据&#xff0c;拦截 Ajax 请求&#xff0c;返回伪造的数据。因此在前端开发阶段就可以通过这个工具进行沉浸式开发&#xff0c;实现数据自产自销&#xff0c;降低和后端的沟通成本&#xff0c;实现真正意义上的前后端开发解耦合。…

2023年轻资产创业怎么做?哪些项目容易创业?

2023年&#xff0c;越来越多的创业者开始考虑轻资产创业&#xff0c;但是&#xff0c;多数人在选择项目的时候&#xff0c;没有一个标准&#xff0c;不知道怎么选择轻资产创业项目&#xff0c;那么&#xff0c;在这里给大家讲讲&#xff0c;轻资产创业怎么做&#xff0c;哪些轻…

反思当下所处的环境,有没有让你停滞不前、随波逐流

环境对人的影响真的很大&#xff0c;小时候的环境、长大后的环境、工作环境、生活环境、好的环境、差的环境......我们都生活在一定的环境中所以既是环境的产物&#xff0c;又是环境的创造者与改造者。我们与环境的关系是相辅相成的我们的生活和工作当中接触到的人或事或物&…