17-事件循环(实现单线程非阻塞的方法就是事件循环)

news2024/11/23 8:15:08

一、是什么

🧀🧀🧀首先,JavaScript是一门单线程的语言,意味着同一时间内只能做一件事,但是这并不意味着单线程就是阻塞,而实现单线程非阻塞的方法就是事件循环

在JavaScript中,所有的任务都可以分为

  • 同步任务:立即执行的任务,同步任务一般会直接进入到主线程中执行
  • 异步任务:异步执行的任务,比如ajax网络请求,setTimeout定时函数等

流程图
在这里插入图片描述
可以看到,同步任务进入主线程,即主执行栈,异步任务进入任务队列,主线程内的任务执行完毕为空,会去任务队列读取对应的任务,推入主线程执行。上述过程的不断重复就事件循环

二、宏任务与微任务

🍕🍳🍕如果将任务划分为同步任务和异步任务并不是那么的准确,举个例子:

console.log(1)
setTimeout(()=>{
	console.log(2)
},0)
new Promise(()=>{
	console.log('new Promise')
	resolve()
}).then(()=>{
	console.log('then')
})
console.log(3)

执行步骤:

  • console.log(1),同步任务,主线程中执行
  • setTimeout() ,异步任务,放到 Event Table,0 毫秒后console.log(2)回调推入 Event Queue 中
  • new Promise ,同步任务,主线程直接执行
  • .then ,异步任务,放到 Event Table
  • console.log(3),同步任务,主线程执行

所以按照分析,它的结果应该是 1 => ‘new Promise’ => 3 => 2 => ‘then’

但是实际结果是:1=>‘new Promise’=> 3 => ‘then’ => 2

出现分歧的原因在于异步任务执行顺序,事件队列其实是一个“先进先出”的数据结构,排在前面的事件会优先被主线程读取

例子中 setTimeout回调事件是先进入队列中的,按理说应该先于 .then 中的执行,但是结果却偏偏相反

原因在于异步任务还可以细分为微任务宏任务

微任务

🍕🍔🍕一个需要异步执行的函数,执行时机是在主函数执行结束之后、当前宏任务结束之前

常见的微任务有:

  • Promise.then
  • MutaionObserver
  • Object.observe(已废弃;Proxy 对象替代
  • process.nextTick(Node.js)

宏任务

🍕🍟🌭宏任务的时间粒度比较大,执行的时间间隔是不能精确控制的,对一些高实时性的需求就不太符合

  • script (可以理解为外层同步代码)
  • setTimeout/setInterval
  • UI rendering/UI事件
  • postMessage、MessageChannel
  • setImmediate、I/O(Node.js)

关系图:
在这里插入图片描述
按照这个流程,它的执行机制是:

  • 执行一个宏任务,如果遇到微任务就将它放到微任务的事件队列中
  • 当前宏任务执行完成后,会查看微任务的事件队列,然后将里面的所有微任务依次执行完
// 遇到 同步任务 console.log(1),直接打印1
// 遇到定时器,属于新的宏任务,留着后面执行
//遇到 new Promise,这个是直接执行的,打印 ‘new Promise'
// .then 属于微任务,放入微任务队列,后面再执行
// 遇到 console.log(3) 直接打印 3
// 本轮宏任务执行完毕,微任务列表查看是否有微任务,发现 .then的回调,执行它,打印’then‘
//当一次宏任务执行完,再去执行新的宏任务,这里就剩一个定时器的宏任务了,执行它,打印 2

三、async和await

🧇🥞🧇是用来声明一个异步方法,而 await是用来等待异步方法执行

async

async函数返回一个promise对象,下面两种方法是等效的

function f(){
	return Promise.resolve('TEST');
}
async function asyncF(){
	return 'TEST';
}

await

正常情况下,await命令后面是一个 Promise对象,返回该对象的结果。如果不是 Promise对象,就直接返回对应的值

async function f(){
	return await 000
}
f().then(v =>console.log(v))//000

不管await后面跟着的是什么,await都会阻塞后面的代码

async function fn1(){
	console.log(1)
	await fn2()
	console.log(2)
}
async function fn2(){
	console.log('fn2')
}
fn1()
console.log(3)

上面的例子中,await 会阻塞下面的代码(即加入微任务队列),先执行 async外面的同步代码,同步代码执行完,再回到 async 函数中,再执行之前阻塞的代码

所以上述输出结果为:1,fn2,3,2

四、流程分析

async function async1() {
    console.log('async1 start')
    await async2()
    console.log('async1 end')
}
async function async2() {
    console.log('async2')
}
console.log('script start')
setTimeout(function () {
    console.log('settimeout')
})
async1()
new Promise(function (resolve) {
    console.log('promise1')
    resolve()
}).then(function () {
    console.log('promise2')
})
console.log('script end')

过程:

  • 执行整段代码,遇到 console.log(‘script start’) 直接打印结果,输出 script start
  • 遇到定时器了,它是宏任务,先放着不执行
  • 遇到 async1(),执行 async1 函数,先打印 async1 start,下面遇到await怎么办?先执行 async2,打印 async2,然后阻塞下面代码(即加入微任务列表),跳出去执行同步代码
  • 跳到 new Promise 这里,直接执行,打印 promise1,下面遇到 .then(),它是微任务,放到微任务列表等待执行
  • 最后一行直接打印 script end,现在同步代码执行完了,开始执行微任务,即 await下面的代码,打印 async1 end
  • 继续执行下一个微任务,即执行 then 的回调,打印 promise2
  • 上一个宏任务所有事都做完了,开始下一个宏任务,就是定时器,打印 settimeout
 console.log('script start')
 console.log('async1 start')
  console.log('async2')
 console.log('promise1')
 console.log('script end')
 console.log('async1 end')
 console.log('promise2')
 console.log('settimeout')
 

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

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

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

相关文章

Vue路由模式

1. vue路由简介和基础使用 1.1 什么是路由 设备和ip的映射关系 接口和服务的映射关系 路径和组件的映射关系 1.2 为什么使用路由? 在一个页面里, 切换业务场景,具体使用示例: 网易云音乐 网易云音乐 单页面应用(SPA): 所有功能在一个html页面上实现 前…

虚拟内存(Virtual Memory)

什么是虚拟内存? 虚拟内存(Virtual Memory) 是计算机系统内存管理非常重要的一个技术,本质上来说它只是逻辑存在的,是一个假想出来的内存空间,主要作用是作为进程访问主存(物理内存)的桥梁并简化内存管理。…

.NET的AsyncLocal用法指南

AsyncLocal用法简介 通过 AsyncLocal 我们可以在一个逻辑上下文中维护一份私有数据,该上下文后续代码中都可以访问和修改这份数据,但另一个无关的上下文是无法访问的。 无论是在新创建的 Task 中还是 await 关键词之后,我们都能够访问前面设…

开关电源——三种基本拓扑

开关电源——三种基本拓扑 开关电源基本原理——伏秒数法则与占空比 当电路是稳态电路的时候,有限的输入对应有限的输出,即电路不再积累能量,电感积累的能量是电压对时间的积分,在开关电源电路中,电感在开关导通和截…

06- c语言预处理 (C语言)

一 预处理概述 1、前面各章中,已经多次使用过 #include 命令。使用库函数之前,应该用#include引入对应的头文件。这种以 #号开头的命令 称为预处理命令。 2、C语言提供了多种预处理功能,如 宏定义、文件包含、条件编译 等。合理地使用预处理…

web漏洞-反序列化之PHPJAVA全解(上)(37)

这个很重要 为什么会产生这个东西:序列化之后便于我们对象的传输和保存,这个作用就是为了数据的传递和格式的转换,我们称之为序列化。 在这给过程中,会涉及到一种叫做有类和无类的情况,开发里面经常看到的一个东西&a…

『免费开源』基于单片机的自动浇花系统DIY总结

功能梳理 PCB线路板采用核心板底板实现 核心板:排针引脚间距为2.54mm,2排,双排间距为2.54mm的倍数(方便与面包板联用),未使用引脚全部引出,核心板上的主芯片为STM32F103RET6。 目的&#xff1a…

ProtoBuf 第一章、初识

一、初识 ProtoBuf 1.1序列化的概念 序列化和反序列化 序列化:把对象转换为字节序列的过程 称为对象的序列化。反序列化:把字节序列恢复为对象的过程 称为对象的反序列化。 什么情况下需要序列化 存储数据:当你想把的内存中的对象状态保存…

Opencv-C++笔记 (12) : opencv-仿射变化

文章目录 一、概述二、GetRotationMatrix2D三、warpAffine() 一、概述 介绍完图像的缩放和翻转后,接下来将要介绍图像的旋转,但是在OpenCV 4中并没有专门用于图像旋转的函数,而是通过图像的仿射变换实现图像的旋转。实现图像的旋转首先需要确…

MT6704 应用

MT6704 是用于反激式变换器的高性能 40V 同步整流器。它兼容各种反激转换器类型。支持 DCM、CCM 和准谐振模式。MT6704 集 成 了 一 个 40V 功 率MOSFET&#xff0c;MT6704可以取代肖特基二极管&#xff0c;提高效率。V SW <V TH-ON 时&#xff0c;内部 MOSFET 导通。 V SW …

【JavaEE】网络层和数据链路层重点协议:IP和以太网

目录 1、IP协议 1.1、IP协议报头 1.2、解决IPv4地址不够用的问题 2、IP地址管理 2.1、IP地址的组成 2.1.1、子网掩码 2.1.2、IP地址的分类 3、路由选择 4、数据链路层协议&#xff1a;以太网协议 1、IP协议 IP协议属于TCP/IP模型的网络层&#xff0c;在网络层协议存在…

volatile,wait和notify,懒汉模式和饿汉模式,阻塞式队列,定时器

目录 可见性 volatile volatile保证内存可见性 volatile不保证原子性 synchronized也可以保证内存可见性 wait和notify wait () notify() notifyAll() wait和sleep对比 顺序执行ABC三个线程 单例模式 饿汉模式 懒汉模式 懒汉模式和饿汉模式在多线程环境下调用getInstance,是否…

将条码图片批量嵌入到Excel单元格中

项目源码&#xff08;如果有帮助希望可以点一个star&#xff09; 业务场景&#xff1a; 需要将条码图片存到excel之中方便归档。 效果展示&#xff1a; 直接运行org.example.Main.main()就会将file目录中的图片插入到excel中&#xff0c;并且在项目根目录会生成一个.xlsx文件…

CTFshow-pwn入门-前置基础pwn20-pwn22

pwn20-pwn22是关于.got节跟.got.plt节的。这3道题的问题描述全是一样的&#xff0c;全都是问.got跟.got.plt是否可写以及他们的地址是什么&#xff0c;然后根据这些信息来拼成flag。那么关于.got和.got.plt的内容非常复杂&#xff0c;这里呢我也不解释了&#xff0c;推荐一个牛…

【kubernetes】负载均衡器安装部署-Haproxy与keepalived

前言:二进制部署kubernetes集群在企业应用中扮演着非常重要的角色。无论是集群升级,还是证书设置有效期都非常方便,也是从事云原生相关工作从入门到精通不得不迈过的坎。通过本系列文章,你将从虚拟机准备开始,到使用二进制方式从零到一搭建起安全稳定的高可用kubernetes集…

不要再用 count(*) 查询记录数了

来源 | 苏三说技术 &#xff08;ID&#xff1a;susanSayJava&#xff09; 已获得原公众号的授权转载 前言 最近我在公司优化过几个慢查询接口的性能&#xff0c;总结了一些心得体会拿出来跟大家一起分享一下&#xff0c;希望对你会有所帮助。 我们使用的数据库是Mysql8&…

【6.19】用户自己写String类会发生什么(双亲委派机制)

用户自己写一个String类会发生什么&#xff1f; 了解“类加载器” Java是运行在Java的虚拟机&#xff08;JVM&#xff09;中的。我们在IDE里编写的Java源代码先编译成.class的字节码文件&#xff0c;再由ClassLoader将class文件加载到JVM中执行。 JVM中有三层ClassLoader&am…

apple pc install windows 10

苹果笔记本安装window10&#xff0c;做个U盘启动&#xff0c;开机狂摁option&#xff0c;选择U盘&#xff0c;当然你最好去windows官方下个镜像&#xff0c;避免我前面出现提出镜像不行。另外苹果后来机器好像不能安windows了。呼呼…

GPT-3解数学题准确率升至92.5%!无需微调即可打造理科语言模型

原文&#xff1a;百度安全验证 【新智元导读】ChatGPT的文科脑有救了&#xff01; 大型语言模型最为人诟病的缺点&#xff0c;除了一本正经地胡言乱语以外&#xff0c;估计就是「不会算数」了。 比如一个需要多步推理的复杂数学问题&#xff0c;语言模型通常都无法给出正确答…

很有必要更新:LightningChart.NET 10.5.1 Crack

LightningChart.NET v10.5.1版本--这个版本比SciChart 更好&#xff0c;更快&#xff0c;更强 为所有3D、Polar和Smith系列添加DataCursor功能。 2023年6月19日-10:53新版 特点 为所有3D、Polar和Smith系列启用了DataCursor功能。DataCursor允许用户浏览一个系列&#xff0…