<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>事件循环 on Last Stand</title><link>https://amatsuzero.github.io/LastStand/tags/%E4%BA%8B%E4%BB%B6%E5%BE%AA%E7%8E%AF/</link><description>Recent content in 事件循环 on Last Stand</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Fri, 08 Nov 2024 00:00:00 +0800</lastBuildDate><atom:link href="https://amatsuzero.github.io/LastStand/tags/%E4%BA%8B%E4%BB%B6%E5%BE%AA%E7%8E%AF/index.xml" rel="self" type="application/rss+xml"/><item><title>事件循环</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-014/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-014/</guid><description>&lt;h2 id="单线程的-javascript"&gt;单线程的 JavaScript&lt;/h2&gt;
&lt;h3 id="同步与异步"&gt;同步与异步&lt;/h3&gt;
&lt;p&gt;JavaScript 在设计之初是作为&lt;strong&gt;浏览器脚本语言&lt;/strong&gt;，主要用于与用户进行&lt;strong&gt;页面交互&lt;/strong&gt;和&lt;strong&gt;操纵 DOM&lt;/strong&gt;。因此，为避免由不可预测的用户操作可能带来的复杂的并发问题，JavaScript 只能设计成&lt;strong&gt;单线程&lt;/strong&gt;的，这也是这门语言的核心特征之一。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;JS 的宿主环境通过仅提供一个线程运行 JS 来保证 JS 代码的单线程运行。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;单线程意味着 JS 引擎在同一时间只能做一件事情，即&lt;strong&gt;同步&lt;/strong&gt;地执行代码。但在代码执行过程中不可避免地会遇到一些&lt;strong&gt;无法立即执行&lt;/strong&gt;的任务，例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;计时器到达时间后要执行的任务 &amp;mdash; &lt;code&gt;setInterval&lt;/code&gt;、&lt;code&gt;setTimeout&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;网络请求完成后要执行的任务 &amp;mdash; &lt;code&gt;XMLHttpRequest&lt;/code&gt;、&lt;code&gt;Fetch&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;监听到用户操作后要执行的任务 &amp;mdash; &lt;code&gt;addEventListener&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&amp;hellip; &amp;hellip; &amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果让执行 JS 的线程去处理这些任务，就会导致该线程处于&lt;strong&gt;长期阻塞&lt;/strong&gt;的状态，而宿主环境中的 JS 执行线程往往还承担着极其重要的工作。例如，在浏览器中，如果执行 JS 的线程长期阻塞，就会导致浏览器卡死！&lt;/p&gt;
&lt;p&gt;为避免上述情况发生，JS 的宿主环境使用了&lt;strong&gt;异步&lt;/strong&gt;的方式来处理这种无法立即执行的任务。&lt;/p&gt;
&lt;p&gt;当遇到异步任务时，宿主环境会将其交给&lt;strong&gt;其他线程&lt;/strong&gt;处理，执行 JS 的线程则会立即结束当前任务转而去执行后续代码。&lt;/p&gt;
&lt;h3 id="事件循环"&gt;事件循环&lt;/h3&gt;
&lt;p&gt;事件循环是宿主环境处理 JS 异步操作，让其能够&lt;strong&gt;非阻塞式运行&lt;/strong&gt;的机制。&lt;/p&gt;
&lt;p&gt;不同宿主环境对事件循环的实现方式有所不同，不过在核心机制上大同小异。&lt;/p&gt;
&lt;p&gt;接下来，本文将详细描述 JavaScript 在&lt;strong&gt;浏览器&lt;/strong&gt;和 &lt;strong&gt;Node.js&lt;/strong&gt; 这两个宿主环境中的事件循环机制。&lt;/p&gt;
&lt;h2 id="浏览器事件循环"&gt;浏览器事件循环&lt;/h2&gt;
&lt;h3 id="浅谈浏览器"&gt;浅谈浏览器&lt;/h3&gt;
&lt;p&gt;聊浏览器的事件循环之前，我们先说说浏览器本身。&lt;/p&gt;
&lt;p&gt;现代浏览器是一个&lt;strong&gt;多进程多线程&lt;/strong&gt;的应用程序，内部工作极其复杂，其程度直逼操作系统。它拥有数个功能模块，为避免单个模块崩溃牵连其他模块，导致连锁反应，使浏览器彻底崩溃。浏览器在启动时，会开启多个进程，把不同的功能模块放在&lt;strong&gt;不同的进程&lt;/strong&gt;里。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-014/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;浏览器进程众多，其中比较&lt;strong&gt;重要&lt;/strong&gt;的有：&lt;/p&gt;
&lt;p&gt;📚 浏览器进程&lt;/p&gt;
&lt;p&gt;浏览器进程是浏览器的&lt;strong&gt;主进程&lt;/strong&gt;，无论打开多少浏览器窗口，它仅有&lt;strong&gt;一个&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;它主要负责浏览器&lt;strong&gt;界面显示&lt;/strong&gt;、&lt;strong&gt;用户交互&lt;/strong&gt;和&lt;strong&gt;进程管理&lt;/strong&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这里说的界面和交互，不是视窗内的网站界面。而是指浏览器本身自带的部分，如导航栏、书签栏、刷新按钮等。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;刚打开浏览器的时候只有一个浏览器进程，其他进程都是它创建的。&lt;/p&gt;
&lt;p&gt;📚 网络进程&lt;/p&gt;
&lt;p&gt;网络进程主要负责处理网站的&lt;strong&gt;数据请求和响应&lt;/strong&gt;，通常情况下，它与&lt;strong&gt;渲染进程&lt;/strong&gt;的交互最为密切。每当网站需要进行资源请求，渲染进程就会将任务交给网络进程处理，网络进程取得响应结果后再返回给渲染进程。&lt;/p&gt;
&lt;p&gt;网络进程内部会开启多个线程，以实现&lt;strong&gt;多网络请求&lt;/strong&gt;的&lt;strong&gt;异步化处理&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;📚 渲染进程&lt;/p&gt;
&lt;p&gt;渲染进程负责控制和显示&lt;strong&gt;视窗&lt;/strong&gt;部分（网站页面）的所有内容，主要是解析 HTML、CSS、JS 和其他资源，并生成渲染树、执行布局和绘制等操作。&lt;/p&gt;</description></item></channel></rss>