ブラウザのイベントループイベントループの完全な理解

序文

  ブラウザのイベントループとノードのイベントループは、すべてのフロントエンドエンジニアが習得しなければならない知識ポイントです。通常、ブラウザを最もよく扱います。この記事ではまずブラウザのイベントループを紹介しますが、作者は以下の観点から問題を分析し、イベントループとは何かを導きます。

  1. オペレーティングシステムのプロセスを知っていますか?スレッドとは何ですか?
  2. JSはシングルスレッドですか、それともマルチスレッドですか?
  3. ブラウザはマルチプロセスですか、それともシングルプロセスですか?なんで?
  4. JSがシングルスレッドの場合、どのようにして非同期処理を実現しますか?
  5. イベントループを引き出す

1.プロセスとは何ですか?スレッドとは何ですか?

  まずは「ModernOperatingSystem」という本をお勧めします。オペレーティングシステムの本質を真に理解すれば、開発上の多くの問題が突然明らかになります。在操作系统中无论是运行系统中的什么应用,最终都是会编译成二进制交CPU给执行。
  私たちの日常のコンピューターの使用では、音楽を聴いたり、コードを書いたり、ブログを書いたりすることがあります。これらのアプリケーションでは、1つまたは複数のプロセスがオペレーティングシステムで開かれ、異なるアプリケーションによって開かれるプロセスは異なります。誰もが理解できるように、アプリケーションで開かれるプロセスは1つだけであり、1つのプロセスで複数のスレッドが開かれると考えられます。スレッドが1つしかない場合は、それをメインスレッドと呼びます。结论:一个进程当中包含多个线程或只有一个主线程。
  プロセスとスレッドの関係をより直感的に理解できるように絵を描きます

1.jpg   この図では、最外層がオペレーティングシステムに相当します。オペレーティングシステムに多くのアプリケーションをダウンロードします。VsCode、Netease Cloud Music、レターなどを実行すると、
  1つのプロセスまたは複数のプロセスが開始されます(これははアプリケーション自体に関連しています)、プロセスには複数のスレッドが含まれます。スレッドが1つしかない場合は、メインスレッドと呼ばれます。
  これを見てもまだプロセスやスレッドについてよくわからない場合は、わかりやすい例でそれらの関係を説明させてください。
  操作系统就跟工厂一样,一个工厂会包含多个车间,其中多个车间就好比是我们的应用程序有多个进程,车间里面有工人在工作,就相当于是线程的概念。

2. JSはシングルスレッドですか、それともマルチスレッドですか。

  答案:JS是单线程。なぜそれがシングルスレッドなのかを掘り下げてみてください。
  実際、JSはブラウザのスクリプト言語であり、その主な目的はユーザー操作の実行とDOMの操作であるため、これはその使用に関連しています。そのため、シングルスレッドでしか実行できません。そうしないと、多くの複雑な同期の問題が発生します。

3.ブラウザはマルチプロセスですか、それともシングルプロセスですか

  答案:浏览器是多进程的。为什么说是多进程的? 你说是就是吗? 凭什么呢?
  当我们浏览网页的时候,有的时候是不是会遇到浏览器卡死的情况。如果我们开了多个会话,就假如我们一边刷力扣,一边开发程序,写循环的时候,写了一个死循环,导致了我们开发的这个会话的崩溃,如果浏览器是单进程的情况下,力扣这个时候也会崩溃。
  当然浏览器肯定不会允许这样的事情发生,它就是多进程的,多个会话互相不影响,你要崩溃你崩溃去,跟我可没关系,哈哈哈哈哈。

4.JS实现异步处理

  首先当您看到了这里,其实你们离成功只有一步之遥了,跟着我继续探讨下去,把Event Loop一点一点捣碎了,喂进你们的嘴里。

  我们先来看一段同步的JS代码

const foo = 'foo'

function bar() {
  console.log('bar')
}

console.log(foo) //foo
bar() //bar

复制代码

  JS的代码执行顺序是从上至下进行的,所以答案如注释所示,我们是毫无疑问的

  现在玩点花样,来一点同步和异步代码给大家看看

const foo = 'foo'

function bar() {
  console.log('bar')
}

queueMicrotask(() => {
  console.log('microtask')
})

console.log(foo) 

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

bar()

//主线程: foo bar
//微任务队列:microtask
//宏任务队列:setTimeout
//执行顺序: foo bar microtask setTimeout(1s过后)

复制代码

  现在穿插了异步的代码,如果把上面从上至下运行代码的结论用到异步,肯定是错误的! 正确的执行顺序的答案,大家可以先看一下,可能对异步不太了解的人会产生疑惑,不要慌,我们一点一点来看,引出下面的事件循环。

5.事件循环

  首先我们又回到 JS 代码是单线程开始讲起,当我们编写的同步的代码的时候,代码的执行顺序是从上至下的,但是当有异步操作或者一些耗时操作的时候,如果还是按照之前的结论从上至下的话,那么一定会堵塞我们主线程的代码 也就是 main script中的代码,这样在js当中肯定是不被允许的。假如我有耗时操作(setTimeout)或者网络请求(ajax),延迟了5s才执行,那我后面的代码都堵塞了。
用文字的形式,还是有点抽象,我们直接上图,到底是一个怎么样的机制,完美解决这一问题。

2.jpg   この図を簡単に説明します。最初に、jsコードはメインスレッドのコード、つまり同期コードを実行します。上から下に、非同期コードが検出されると、ブラウザーに渡され、ブラウザーが開きます。ブラウザスレッドがこれらの2つのキューを維持する特別なスレッド一个微任务队列,一个宏任务队列
  注意:每一次执行宏任务之前,都是要确保我微任务的队列是空的,也就是说从代码执行的顺序来说微任务优先于宏任务。
  ただし、キューをカットする状況があります。つまり、マイクロタスクの実行を終了し、マクロタスクの実行を開始すると(複数のマクロタスクがあります)、マクロのキュー内のコードがタスクキューが実行され、マクロタスクキューに別のマイクロタスクコードがあり、マイクロタスクをマイクロタスクキューに入れます。
  このときは特に注意してください!厳密に言えば、最初にコンパイルされるマクロタスクが続きますが、このとき、マイクロタスクには、タスクが直接実行されるのではなく、実行される前に実行されるマイクロタスクキューがあります。これらの非同期コードは、実行のためにjsに渡され这样三者形成了一个闭环,我们称之为事件循环ます。

おすすめ

転載: juejin.im/post/7079092748929728548