首页/文章/javascript

不了解事件循环EventLoop的不是一个好前端er

2024-07-12
14135 分钟
...

JavaScript是单线程的脚本语言,意味着它一次只能执行一个任务。然而,现代Web应用常常需要处理异步操作,如网络请求、定时器等,为了让线程不阻塞,Event Loop出现了,它是JavaScript引擎管理异步操作的核心机制。

在Event Loop的学习之前,我们得先弄懂栈与队列这两种数据结构以及JavaScript中的宏任务与微任务

  • 栈(stack):一种先进后出的数据结构,就像一个桶,最先放的得最后才能拿出来。

  • 队列(queue):先进先出,就像一个只有一条道的隧道,先进去的车子先出来。

概述

EventLoop(事件循环)是编程中管理异步操作和非阻塞IO的一种重要机制,它的目的就是让程序可以在等待某些耗时操作(如网络请求、定时器等)完成的同时,能够执行其他任务,从而避免程序阻塞。换句话说,我在等咖啡的同时EventLoop让我可以边写文章而不是发呆坐在那。

图解

Event Loop的大概流程:

任务在要被执行时会被分为同步和异步任务,同步任务正常执行,如果是异步任务就先放进Event Table中,比如在执行时碰到了一个定时器settimeout,它就会被放入Table中,同时定时器开始计时,当时间结束时它进入Event Queue,在这里面满足先进先出的原则,先来的就会更早来到主线程运行,这样我们的异步任务就不会阻塞我们的同步任务了。

JavaScript中任务被分为两种,一种叫宏任务,一种叫微任务,它们在Event Loop机制中也扮演着至关重要的角色,与各种异步任务的执行顺序息息相关

  • 宏任务(Macro Task)
  1. 整个script
  2. 定时器任务,如setTimeoutsetInterval
  3. 浏览器事件,如clickmouseover
  4. 网络请求,如fetchXMLHttpRequest
  5. UI渲染,如重绘。
  • 微任务(Micro Task)
  1. Promise的回调函数
  2. Async/Await 函数
  3. MutationObserver的回调函数
  4. process.nextTick Node.js环境下

执行顺序

先执行整个script这个宏任务,其中会包含各种小的宏任务以及微任务,从上至下,碰到同步任务就执行,碰到宏任务先放进宏任务队列,碰到微任务就放到微任务队列,当script这个宏任务执行到底时,就开始执行微任务队列里面的任务,执行完里面的微任务后去宏任务队列拿一个任务出来,如果这个宏任务里面又有许多微任务那就照样放进微任务队列,等待这个宏任务执行完后再执行微任务队列中的任务。

总结一下:最开始执行的一定是宏任务,然后这个宏任务中的微任务会先于其中的宏任务执行。

说再多都不如来个例子

console.log("Start");       
setTimeout(() => {          
  console.log("In Timeout");
  setTimeout(() => {           
    console.log("timeover");
  })
  Promise.resolve().then(function() {    
    console.log('promise2');
  });
});
Promise.resolve().then(function() {     
    console.log('promise1');
  });
console.log("End");     

输出:

解析(从上往下):

  1. 同步任务先执行,毋容置疑,Start直接输出。
  2. 将第一个settimeout(第2行)放入宏任务队列。
  3. 把promise(第11行)放入微任务队列。
  4. 输出End
  5. 整个script这个宏任务执行完毕,检查微任务队列,发现promise(第11行),执行输出promise1
  6. 微任务队列清空,执行下一个宏任务settimeout(第2行),同步任务直接输出In Timeout
  7. 将settimeout(第4行)放入宏任务队列。
  8. 把promise(第7行)放入微任务队列。
  9. settimeout(第2行)这个宏任务执行完毕,检查微任务队列,发现promise(第7行),执行输出promise2
  10. 微任务队列清空,执行下一个宏任务settimeout(第4行),输出timeover

如果您觉得这篇文章有帮助,请点个赞吧~

分享文章

相关文章

更多文章 →
javascript2025-09-18
JavaScript 的多线程能力:Worker
如果你写过一些计算量稍大的 JavaScript 代码,比如图像处理、大量数据排序或者复杂的算法,你几乎肯定遇到过浏览器“卡死”的现象。点击页面没反应,动画也停了,就像整个世界都静止了。 这就是主线程被阻塞的典型后果。因为主线程既要负责执行 JavaScript,又要负责渲染页面、响应用户操作,一旦它被繁重的计算任务占满,就无暇顾及其他,用户体验便直线下降。 这个问题的根源,正是“主线程是单线程的”。那么,如何解决呢? 答案很简单:把这...
学习面试
javascript2025-09-10
手把手教你实现一个EventEmitter
你是不是也遇到过这种情况:代码里各种事件监听和触发,回调函数套了一层又一层,最后自己都理不清哪个事件先触发、哪个后触发了? 别担心,今天我就带你从零开始实现一个自己的事件触发器(EventEmitter),让你彻底掌握事件驱动的精髓,代码清晰度直接提升200%! 为什么要懂EventEmitter? 先说说为什么我们要关心这个。Node.js的核心就是事件驱动,比如文件读写、网络请求,都是通过事件来处理的。不会EventEmitter,...
学习面试
javascript2025-08-09
Web Worker 多线程魔法
你是否曾遇到过网页因为复杂计算而卡顿的情况?今天,让我们一起探索Web Worker的神奇世界,看看如何用多线程技术解决性能瓶颈,并实现流畅的图片压缩功能! 为什么需要Web Worker? 想象一下,你在一个繁忙的餐厅里,只有一位服务员(主线程)负责点餐、上菜、结账所有工作。当客人突然暴增时,这位服务员就会手忙脚乱,其他客人只能干等着… 这就是JavaScript的现状—— 单线程 !所有任务都在一个线程中排队执行,一旦遇到复杂计算(...
学习面试
javascript2025-08-07
🌐AST抽象语法树
AST 是前端开发中一个非常重要的概念,它就像是代码的“编译器”,能够帮助我们理解和操作代码。本文将深入探讨 AST 的原理和应用,带你从零开始了解 AST。 一、什么是 AST? AST(抽象语法树)是一种树形结构,用于表示程序代码的语法结构。它将代码分解为一系列的节点,每个节点代表代码中的一个元素,如变量、函数、表达式等。AST 是编译器和解释器的基础,也是代码分析和转换的关键工具。 1\. AST 的结构 AST 的结构通常包括以...
学习面试
javascript2025-08-05
打字机效果是如何实现的
分析效果 使用 AI 对话的时候,文字是一个字一个字蹦出来的?它不是等所有内容生成完毕后一次性展示,而是以一种流畅、实时的“打字机”效果呈现,这种体验的背后,隐藏着一种高效的Web技术。它就是 服务器推送事件(Server Sent Events,简称 SSE) 什么是 SSE 从根本上说,SSE 是一种允许服务器 单向 、 持续 地向客户端(浏览器)推送数据的Web技术。 可以把它想象成一个 电台广播 : 服务器 是广播电台,持续不断...
学习面试
javascript2025-08-04
Promise 从原理到实现
前言 是 异步编程的核心概念之一,它为我们提供了一种更优雅的方式来处理异步操作。 本文将全面剖析 的工作原理,并逐步实现一个符合 规范的 。 正文 一、Promise 基础概念 代表一个异步操作的最终完成(或失败)及其结果值。它有 种状态: 1. pending : ,既不是成功,也不是失败状态 2. fulfilled :意味着操作 完成 3. rejected :意味着操作 状态一旦改变就不能再变,只能从 变为 ,或从 变为 。 二...
学习面试

评论

请登录后发表评论

去登录
加载评论中...

目录