一文搞定 EventLoop、宏任务、微任务

面试官:你了解JavaScript事件循环吗,掌握多少,把你知道的都说一下。

今天我们就来说一下,JavaScript作为一门单线程语言,如何通过事件循环(Event Loop)和任务队列(Task Queue)的机制,高效地处理异步任务,保证用户体验的流畅性。在本文中,我们将详细探讨事件循环、任务队列,以及在实际开发中的一些应用场景(面试常见笔试题)。

为什么面试官喜欢问事件循环机制

JavaScript是一门单线程语言,单线程意味着JavaScript代码在执行时,只能有一个主线程来处理所有的任务。单线程是有必要的,因为JavaScript最初主要的执行环境是浏览器,JavaScript面对着各种各样的操作,比如操作dom,css等。如果是多线程执行,则很难在频繁操作的情况下保证它的一致性。即便保证了一致性,对性能也有较大的影响。后来为了实现多线程,引入了web worker,但是对该技术的使用却有诸多限制。

事件循环概述

在事件循环中,当主线程执行完当前的同步任务后,会检查事件队列中是否有待处理的事件。如果有,主线程会取出事件并执行对应的回调函数。这个循环的过程被称为事件循环(Event Loop),它由主线程和任务队列两部分组成。主线程负责执行同步任务,而异步任务则通过任务队列进行处理。这种机制保证了异步任务在适当的时机能够插入执行,从而实现了JavaScript的非阻塞异步执行。
在这里插入图片描述

事件循环流程如下:

主线程读取JavaScript代码,形成相应的堆和执行栈。
当主线程遇到异步任务时,将其委托给对应的异步进程(如Web API)处理。
异步任务完成后,将相应的回调函数推入任务队列。
主线程执行完同步任务后,检查任务队列,如果有任务,则按照先进先出的原则将任务推入主线程执行。
重复执行以上步骤,形成事件循环。

同步任务

同步任务是按照代码的书写顺序一步一步执行的任务。当主线程执行同步任务时,会阻塞后续的代码执行,直到当前任务执行完成。典型的同步任务包括函数调用、变量赋值、算术运算等。例如:
console.log(‘Step 1’);

let result = add(2, 3);
console.log(result);
console.log('Step 2');

function add(a, b) {
  return a + b;
}

在上面的例子中,console.log(‘Step 1’) 执行完毕后才会执行函数调用 add(2, 3),并等待 add 函数返回结果后才会继续执行后续代码。

异步任务

异步任务是在主线程执行的同时,通过回调函数或其他机制委托给其他线程或事件来处理的任务。在执行异步任务时,主线程不会等待任务完成,而是继续执行后续代码。包括:

回调函数 callback
Promise/async await
Generator
事件监听
发布/订阅
计时器
requestAnimationFrame
MutationObserver
process.nextTick
I/O操作
不得不说,异步执行的机制使得 JavaScript 能够更好地处理耗时操作,保持页面的响应性。

console.log('Start');

setTimeout(() => {
  console.log('Timeout callback');
}, 1000);

console.log('End');

在上述例子中,setTimeout 是一个异步任务,它会在1秒后将回调函数推入任务队列,而主线程不会等待这个1秒,而是继续执行后面的 console.log(‘End’)。当主线程的同步任务执行完成后,它会检查任务队列,将异步任务的回调函数推入执行栈,最终输出 ‘Timeout callback’。

任务队列

上面我们讨论了同步任务和异步任务的执行过程,接下来我们将进一步探讨任务队列,了解它的最小颗粒度是如何执行的。

任务队列类型

任务队列分为宏任务队列(macrotask queue)和微任务队列(microtask queue)两种。JavaScript 引擎遵循事件循环的机制,在执行完当前宏任务后,会检查微任务队列,执行其中的微任务,然后再取下一个宏任务执行。这个过程不断循环,形成事件循环。

1、宏任务(Macrotasks)是一些较大粒度的任务,包括:

所有同步任务
I/O操作,如文件读写、数据库数据读写等
setTimeout、setInterval
setImmediate(Node.js环境)
requestAnimationFrame
事件监听回调函数等

2、微任务(Microtasks)是一些较小粒度、高优先级的任务,包括:

Promise的then、catch、finally
async/await中的代码
Generator函数
MutationObserver
process.nextTick(Node.js 环境)

任务执行过程

首先,必须要明确,在JavaScript中,所有任务都在主线程上执行。任务执行过程分为同步任务和异步任务两个阶段。异步任务的处理经历两个主要阶段:Event Table(事件表)和 Event Queue(事件队列)。

Event Table存储了宏任务的相关信息,包括事件监听和相应的回调函数。当特定类型的事件发生时,对应的回调函数被添加到事件队列中,等待执行。例如,你可以通过addEventListener来将事件监听器注册到事件表上:

document.addEventListener('click', function() {
  console.log('Hello world!');
});

微任务与 Event Queue 密切相关。当执行栈中的代码执行完毕后,JavaScript引擎会不断地检查事件队列。如果队列不为空,就将队列中的事件一个个取出,并执行相应的回调函数。

在这里插入图片描述

任务队列的执行流程可概括为:

同步任务在主线程排队执行,异步任务在事件队列排队等待进入主线程执行。
遇到宏任务则推进宏任务队列,遇到微任务则推进微任务队列。
执行宏任务,执行完毕后检查当前层的微任务并执行。
继续执行下一个宏任务,执行对应层次的微任务,直至全部执行完毕。

这个流程确保了异步任务能够在适当的时机插入执行,保持程序的高效性和响应性。

如果看到这里,还觉得有点懵,我们不妨看看下面这个示例解析,一定会让你清晰明了!!!

示例解析(很重要!这也是面试常考笔试题)

实例1:

console.log(1);
setTimeout(() => {
    console.log(2);
}, 0);
console.log(3);
new Promise((resolve) => {
    console.log(4);
    resolve();
    console.log(5);
}).then(() => {
    console.log(6);
});
console.log(7);

1
3
4
5
7
6
2

1.创建Promise实例是同步的,所以1、3、4、5、7是同步执行的。
2.then方法是微任务,放入微任务队列中,在当前脚本执行完毕后立即发生。
3.同步任务执行完毕后,执行微任务队列中的微任务。
4.最后,setTimeout放入宏任务队列,按照先进先出的原则执行。

实例2:

console.log(1)
setTimeout(()=>{
    Promise.resolve().then(()=>{
        console.log(2)
    })
    console.log(3)
},0)
new Promise((resolve)=>{
    for(let i =0;i<=1000;i++){
        if(i===1000){
            resolve();
        }
    }
    console.log(4) 
}).then(()=>{
    console.log(5)
})
console.log(6)

1
4
6
5
3
2

注意:出现async、await,等价于promise、then。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CTFHUB-技能树-Web前置技能-文件上传(无验证,JS前端验证,前端验证)

CTFHUB-技能树-Web前置技能-文件上传&#xff08;无验证&#xff0c;JS前端验证&#xff0c;前端验证—.htaccess&#xff09; 文章目录 CTFHUB-技能树-Web前置技能-文件上传&#xff08;无验证&#xff0c;JS前端验证&#xff0c;前端验证—.htaccess&#xff09;文件上传无验…

关联规则挖掘(二)

目录 三、FP-增长算法&#xff08;一&#xff09;算法的背景&#xff08;二&#xff09;构造FP-树&#xff08;三&#xff09;生成频繁项集 四、关联规则的评价&#xff08;一&#xff09;支持度和置信度的不足&#xff08;二&#xff09;相关性分析 三、FP-增长算法 &#xf…

C++内存管理——new/delete、operator new/operator delete

内存管理 int globalVar 1; static int staticGlobalVar 1; void Test() {static int staticVar 1;int localVar 1;int num1[10] { 1, 2, 3, 4 };char char2[] "abcd";const char* pChar3 "abcd";int* ptr1 (int*)malloc(sizeof(int) * 4);int* pt…

tcp三次握手和四次断开以及tcpdump的基本使用

前言 最近工作中会发现有超时的问题&#xff0c;还有就是在面试的时候很多都要求深入理解TCP/IP协议。突然感觉TCP/IP协议是一个既熟悉&#xff0c;又陌生的技术。又想到上大学的时候&#xff0c;老师说过 网络的圣经&#xff1a;“TCP/IP详解” 卷一 卷二 卷三&#xff0c;三…

IIC总线读取温度湿度传感器数据实验

iic.c #include "iic.h"extern void printf(const char* fmt, ...); /** 函数名 &#xff1a; delay_us* 函数功能&#xff1a;延时函数* 函数参数&#xff1a;无* 函数返回值&#xff1a;无* */ void delay_us(void) //微秒级延时 {unsigned int i 2000;while(i-…

性能工具之emqtt-bench BenchMark 测试示例

文章目录 一、前言二、典型压测场景三、机器准备四、典型压测场景1、并发连接2、消息吞吐量测试2.1 1 对 1&#xff08;示例&#xff09;2.2 多对1&#xff08;示例&#xff09;2.3 1对多&#xff08;示例&#xff09; 五、遇到的问题client(): EXIT for {shutdown,eaddrnotava…

java学习之路-多态

文章目录 目录 文章目录 前言 1.多态 1.1 多态的概念 1.2 多态实现条件&#xff08;重点&#xff09; 多态实现的栗子 1.3重写 重写的规则 重写和重载的区别 1.4静态和动态绑定 1.5向上转型和向下转型 1.向上转型 2.向下转型 1.6多态的优点 前言 本文内容&#xff1a;多…

DHCP是什么意思 路由器中DHCP服务器怎么设置?

概述 DHCP是什么意思&#xff1f;很多朋友在路由器设置中&#xff0c;都会看到有一项“DHCP服务器”设置功能&#xff0c;而很多朋友对这个功能不太了解&#xff0c;也不知道怎么设置。其实&#xff0c;对于普通用户来说&#xff0c;无需去单独设置路由器DHCP服务器功能&#…

李沐46_语义分割和数据集——自学笔记

语义分割 语义分割将图片中的每个像素分类到对应的类别。 实例分割&#xff08;目标检测的进化版本&#xff09; 如果有物体&#xff0c;会区别同一类的不同物体。 语义分割重要数据集&#xff1a;Pascal VOC2012 %matplotlib inline import os import torch import torch…

【强化学习的数学原理-赵世钰】课程笔记(九)策略梯度方法(Policy Gradient Method)

目录 一.policy gradient 的基本思路&#xff08;Basic idea of policy gradient&#xff09; 二.定义最优策略的 metrics&#xff0c;也就是 objective function 是什么 三.objective function 的 gradient 四.梯度上升算法&#xff08;REINFORCE&#xff09; 五.总结 上…

DevExpress WinForms中文教程 - 如何通过UI测试自动化增强应用可靠性?(二)

DevExpress WinForm拥有180组件和UI库&#xff0c;能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForm能完美构建流畅、美观且易于使用的应用程序&#xff0c;无论是Office风格的界面&#xff0c;还是分析处理大批量的业务数据&#xff0c;它都能轻松胜任…

数字工厂管理系统与MES系统有什么区别

随着工业4.0时代的到来&#xff0c;数字化转型已经成为制造企业发展的必然趋势。在这个过程中&#xff0c;数字工厂管理系统和MES管理系统都扮演者至关重要的角色。然而&#xff0c;尽管两者都致力于优化生产流程和提高生产效率&#xff0c;但它们在实际应用、功能定位和系统架…

Datapump数据迁移方案

环境准备 确认源数据库和目标数据库的版本 确保源数据库和目标数据库的Oracle版本兼容&#xff0c;以保证Datapump工具能够正常工作。 硬件资源检查 确认源数据库和目标数据库服务器的硬件资源&#xff08;如CPU、内存、存储空间&#xff09;能够满足数据迁移的需求。 网络连…

基于STM32的智能垃圾分类识别系统设计(论文)_kaic

摘 要 智能垃圾分类技术逐渐受到了政府的重视和支持&#xff0c;越来越多的城市开始推行垃圾分类政策。因此设计一款能够对垃圾进行识别并分类的控制系统具有一定的现实意义。本设计采用STM32单片机作为整个系统的控制核心&#xff0c;利用K210开发板作为图像识别控制系统&…

在Postgres中,如何有效地管理大型数据库的大小和增长

文章目录 一、定期清理和维护1. VACUUM和ANALYZE2. 删除旧数据和归档 二、分区表三、压缩数据四、配置优化1. 调整维护工作负载2. 监控和日志 五、使用外部存储和扩展1. 外部表和FDW2. 扩展和插件 六、定期备份和恢复测试结论 管理大型数据库的大小和增长是数据库管理员&#x…

如何看懂电路图,理解电流回路

任何电器都需要电源来供电。电源有正极(+)和负极(-),为了向负载提供电力,电流必须从正极流出,通过负载后再回到负极。这构成了一个供电电流回路,负载得到电力供应后才能开始工作。如果其中的某个环节断开,就无法形成供电电流回路,负载将得不到供电,也无法正常工作。 在一…

Typescript 总结3——类

一、是什么 类&#xff08;Class&#xff09;是面向对象程序设计&#xff08;OOP&#xff0c;Object-Oriented Programming&#xff09;实现信息封装的基础 类是一种用户定义的引用数据类型&#xff0c;也称类类型 传统的面向对象语言基本都是基于类的&#xff0c;JavaScript …

机器学习与深度学习 --李宏毅(笔记与个人理解)Day 20

Day 20 RNN 2 实际使用和其他应用 在实际的学习&#xff08;training&#xff09;过程中是如何工作的&#xff1f; step 1 Loss step 2 training Graindent Descent 反向传播的进阶版 – BPTT CLIpping 设置阈值~ 笑死昨天刚看完关伟说的有这玩意的就不是好东西 Why&#xff1…

window轻松使用k8s

Docker Desktop安装篇 1、win安装 1、下载安装包 https://www.docker.com/products/docker-desktop/ 官网下载安装包 2、配置win支持虚拟化 不勾选Hyper-V&#xff0c;它和Windows Subsystem for Linux (WSL) 是两套功能&#xff0c;这里不选他 3、安装WSL配置window支持lin…

2024电容笔专业对比评测:西圣、倍思、绿联哪款平替电容笔更好用?

在当今学习和工作环境中&#xff0c;iPad作为一种多功能的学习和生产力工具&#xff0c;受到越来越多人的青睐与需求。然而&#xff0c;要充分发挥iPad的功能&#xff0c;一个优质的电容笔是必不可少的配件之一。电容笔不仅可以帮助用户进行手写笔记、绘画创作&#xff0c;还能…