検索
ホームページウェブフロントエンドjsチュートリアルブラウザ UI マルチスレッドと JavaScript シングルスレッドの基礎となる動作メカニズムの理解

初めて JavaScript を学んだときから、私はこの考えを「植え付けられ」ました

JavaScript はシングルスレッドです
しかし、継続的な学習プロセスで
タイマーと ajax の非同期読み込みについて学びました
この文を疑ってください
JavaScript はシングルスレッドであるのに、なぜ依然として非同期読み込みが行われるのでしょうか?
後で、ブラウザには js スレッドだけではなく、他のスレッドと一緒に存在することを知りました - ブラウザ UI マルチスレッド

このような記事をずっと書きたいと思っていましたが、私は十分に理解していませんが、私の書いたことが皆さんを誤解させるのではないかと心配です
ネット上で皆さんが書いたさまざまなブログ記事を読んで、私はさらに混乱しました
でも、最終的には勇気を出して決意しました。それについて話しましょう╮(╯_╰)╭
さて、JavaScript のスレッドは脇に置いてください問題については話さないで、まずブラウザ UI スレッドとは何かを見てみましょう

ブラウザ UI マルチスレッド

前の写真を見てみましょうまず

ブラウザ UI マルチスレッドと JavaScript シングルスレッドの基礎となる動作メカニズムの理解

通常の状況では、ブラウザには少なくとも 3 つの常駐スレッドがあります

  • GUI レンダリング スレッド (ページのレンダリング)

  • JS エンジン スレッド (処理スクリプト)

  • イベントトリガースレッド (制御インタラクション)

ブラウザを含むと、新しいスレッドが開かれることがあります。たとえば、Http リクエスト スレッド (Ajax) と使用後に破棄されるその他のスレッド
これらは一緒になってブラウザの UI スレッドを構成します
これらのスレッドは機能しますUIスレッドの制御下で整然とした方法で実行されます
この常駐スレッドに関するオンラインの意見は一貫性がありません。各ブラウザの実装は異なる可能性があるため、ここでは詳しく説明しません

jsエンジンスレッドを右下隅、これはブラウザのメインスレッドです
そして、GUI レンダリング スレッドとは互換性がありません
理由は非常に簡単で、すべての JS スレッドを操作する必要があるからです。特定の DOM スタイルが必要な場合、レンダリング エンジンの動作を停止する必要があります (横暴な社長が、そこに立って動かないように要求します)

js シングルスレッド

JavaScript がシングルスレッドである理由
シングルスレッドとは、次のことしか実行できないことを意味します同時に 1 つのことを実行します
それでは、JavaScript がマルチスレッドであることは良くないのでしょうか? それはどれほど効率的ですか?
それは良くありません
js はユーザーと対話し、DOM を処理するように設計されています
JavaScript がマルチスレッドである場合、マルチスレッド同期の問題に対処する必要があります (C++ スレッド同期に支配される恐怖を漠然と覚えています)
js がマルチスレッドの場合、同時に 1 つのスレッドが DOM を変更したいと考え、別のスレッドが DOM を変更したいと考えます。 DOMを削除してください
問題はさらに複雑になります。「ロック」メカニズムが導入されると、それは非常に面倒になります(それではフロントエンドを学ばなくなります( ̄_ , ̄))
なので、私たちのようなスクリプト言語を開発する必要はありません。非常に複雑なので、JavaScriptは誕生以来シングルスレッドで実行されています

H5はWeb Workerを提案しましたが、DOMを操作することはできません。それを解決するには、まだ兄貴分の JS メインスレッドに任せる必要があります
この Web Worker についてはあまり詳しくないので、ここで説明します。あまり言うことはありません
これらのサブスレッドはメインスレッドによって完全に制御されているため、 JavaScript のシングルスレッドの性質は変わりません

実行スタック

まず実行スタックとは何かを見てみましょう
スタックは先入れ後出し (FILO) データです構造
実行スタックには格納されます実行されるタスク。各タスクは「フレーム」と呼ばれます
たとえば

function foo(c){
    var a = 1;
    bar(200);
}function bar(d){
    var b = 2;
}
foo(100);

実行スタックがどのように変化したかを見てみましょう

  • 最初、コードが実行されていないとき、実行スタックはfoo 関数が実行されると、フレームが作成され、このフレームには仮パラメータとローカル変数が含まれます (プリコンパイル プロセス)。その後、関数内のコードが実行されます。

  • 新しいフレームを作成します。これには仮パラメータとローカル変数も含まれ、スタックにプッシュされます

  • bar関数が実行された後、スタックがポップされます

  • foo関数が実行されます、そしてスタックはポップされます

  • 実行スタックは空です

  • 実行スタックは実際にはJSメインスレッドと同等です

  • タスクキュー
  • キューは先入れ先出し(FIFO)データです構造

    js スレッドにもタスク キューがあります
  • タスク キューには一連の保留中のタスクが含まれます
単一スレッドとは、すべてのタスクを次々に実行する必要があることを意味します。1 つのタスクの実行に時間がかかりすぎると、後続のタスクが実行されなくなります。待たなければなりません

それは、看護師が列に並んでいる子供に注射をするようなものです。前の子供が針を転がし続けると、後ろの子供は待たなければなりません(この比喩は不適切だと思われます)

しかし、もし子供が前の子が針で気を失いました

そのとき、看護師のおばさんはそこに座って彼を待つことができません。目が覚めたら、まず後ろの子供に鍼を打たなければなりません

これは、その子供を(非同期的に)「首を吊る」ことに等しいです


、タスクは 2 つのタイプに分けることができます



同期タスク

非同期タスク

同步任务就是正在主线程执行栈中执行的任务(在屋子内打针的小朋友)
而异步任务是在任务队列等候处理的任务(在屋子外等候打针的小朋友)
一旦执行栈中没有任务了,它就会从执行队列中获取任务执行

事件与回调

任务队列是一个事件的队列,IO设备(输入/输出设备)每完成一项任务,就会在任务队列中添加事件处理
用户触发了事件,也同样会将回调添加到任务队列中去
主线程执行异步任务,便是执行回调函数(事件处理函数)
只要执行栈一空,排在执行队列前面的会被优先读取执行,
不过主线程会检查时间,某些事件需要到了规定时间才能进入主线程处理(定时器事件)

事件循环

主线程从执行队列不断地获取任务,这个过程是循环不断地,叫做“Event Loop”事件循环
同步任务总是会在异步任务之前执行
只有当前的脚本执行完,才能够去拿任务队列中的任务执行
前面也说到了,任务队列中的事件可以是定时器事件
定时器分为两种 setTimeout() 和 setInterval()
前者是定时执行一次,后者定时重复执行
第一个参数为执行的回调函数,第二个参数是间隔时间(ms)
来看这样一个例子

setTimeout(function(){
    console.log('timer');
},1000);console.log(1);console.log(2);console.log(3);

这个没什么问题,浏览器打印的是 1 2 3 timer
但是这样呢

setTimeout(function(){
    console.log('timer');
},0);//0延时console.log(1);
console.log(2);
console.log(3);

浏览器打印依然打印的是 1 2 3 timer
也许有同学知道,旧版浏览器,setTimeout定时至少是10ms(即便你设置了0ms),
H5新规范是定时至少4ms(我读书少不知道为什么),改变DOM也是至少16ms
也许这是因为这个原因
那么我再改动一下代码

setTimeout(function(){
    console.log('timer');
},0);var a = +new Date();for(var i = 0; i < 1e5; i++){
    console.log(1);
}var b = +new Date();
console.log(b - a);

这回够刺激了吧,输出10w次,我浏览器都假死了(心疼我chrome)
不仅如此,我还打印了循环所用时间
来看看控制台

输出了10w个1,用了将近7s
timer依然是最后打印的
这就证明了我前面说的话: 同步任务总是会在异步任务之前执行
只有我执行栈空了,才会去你任务队列中取任务执行

实例

最后我举一个例子加深一下理解

demo.onclick = function(){
    console.log(&#39;click&#39;);
}function foo(a){
    var b = 1;
    bar(200);
}function bar(c){
    var d = 2;
    click//伪代码 此时触发了click事件(这里我假装程序运行到这里手动点击了demo)
    setTimeout(function(){
        console.log(&#39;timer&#39;);
    }, 0);
}
foo(100);

怕大家蒙我就不写Ajax了
Ajax如果处理结束后(通过Http请求线程),也会将回调函数放在任务队列中
还有一点click那一行伪代码我最开始是想用demo.click()模拟触发事件
后来在测试过程中,发现它好像跟真实触发事件不太一样
它应该是不通过触发事件线程,而是存在于执行栈中,就相当于单纯地执行click回调函数
不过这只是我自己的想法有待考证,不过这不是重点,重点是我们理解这个过程,请大家不要吐槽我╰( ̄▽ ̄)╭

下面看看执行这段代码时发生了什么(主要说栈和队列的问题,不会赘述预编译过程)

  • 主线程开始执行,产生了栈、堆、队列

  • demo节点绑定了事件click,交给事件触发线程异步监听

  • 执行foo函数(之前同样有预编译过程),创建了帧包括foo函数的形参、局部变量压入执行栈中

  • foo函数内执行bar函数,创建帧包括bar函数的形参、局部变量压入执行栈中

  • 触发了click事件,事件触发线程将回调事件处理函数放到js线程的任务队列中

  • 触发了定时器事件,事件触发线程立即(4ms)将回调处理函数放到js线程的任务队列中

  • bar函数执行完毕,弹出栈

  • foo函数执行完毕,弹出栈

  • 此时执行栈为空

  • 执行栈向任务队列中获取一个任务:click回调函数,输出‘click’

  • 执行栈项任务队列中获取一个任务:定时器回调函数,输出‘timer’

  • 执行结束

这里从任务队列里不断取任务的过程就是Event Loop

Event Loop

有一些我的理解,如果发现不对或者有疑问的地方,请联系我
相信大家看了这个例子应该对js底层运行机制有了一个大概的了解

 以上就是ブラウザ UI マルチスレッドと JavaScript シングルスレッドの基礎となる動作メカニズムの理解及对JavaScript单线程底层运行机制的理解的内容,更多相关内容请关注PHP中文网(www.php.cn)!


声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
JavaScript in Action:実際の例とプロジェクトJavaScript in Action:実際の例とプロジェクトApr 19, 2025 am 12:13 AM

現実世界でのJavaScriptのアプリケーションには、フロントエンドとバックエンドの開発が含まれます。 1)DOM操作とイベント処理を含むTODOリストアプリケーションを構築して、フロントエンドアプリケーションを表示します。 2)node.jsを介してRestfulapiを構築し、バックエンドアプリケーションをデモンストレーションします。

JavaScriptとWeb:コア機能とユースケースJavaScriptとWeb:コア機能とユースケースApr 18, 2025 am 12:19 AM

Web開発におけるJavaScriptの主な用途には、クライアントの相互作用、フォーム検証、非同期通信が含まれます。 1)DOM操作による動的なコンテンツの更新とユーザーインタラクション。 2)ユーザーエクスペリエンスを改善するためにデータを提出する前に、クライアントの検証が実行されます。 3)サーバーとのリフレッシュレス通信は、AJAXテクノロジーを通じて達成されます。

JavaScriptエンジンの理解:実装の詳細JavaScriptエンジンの理解:実装の詳細Apr 17, 2025 am 12:05 AM

JavaScriptエンジンが内部的にどのように機能するかを理解することは、開発者にとってより効率的なコードの作成とパフォーマンスのボトルネックと最適化戦略の理解に役立つためです。 1)エンジンのワークフローには、3つの段階が含まれます。解析、コンパイル、実行。 2)実行プロセス中、エンジンはインラインキャッシュや非表示クラスなどの動的最適化を実行します。 3)ベストプラクティスには、グローバル変数の避け、ループの最適化、constとletsの使用、閉鎖の過度の使用の回避が含まれます。

Python vs. JavaScript:学習曲線と使いやすさPython vs. JavaScript:学習曲線と使いやすさApr 16, 2025 am 12:12 AM

Pythonは、スムーズな学習曲線と簡潔な構文を備えた初心者により適しています。 JavaScriptは、急な学習曲線と柔軟な構文を備えたフロントエンド開発に適しています。 1。Python構文は直感的で、データサイエンスやバックエンド開発に適しています。 2。JavaScriptは柔軟で、フロントエンドおよびサーバー側のプログラミングで広く使用されています。

Python vs. JavaScript:コミュニティ、ライブラリ、リソースPython vs. JavaScript:コミュニティ、ライブラリ、リソースApr 15, 2025 am 12:16 AM

PythonとJavaScriptには、コミュニティ、ライブラリ、リソースの観点から、独自の利点と短所があります。 1)Pythonコミュニティはフレンドリーで初心者に適していますが、フロントエンドの開発リソースはJavaScriptほど豊富ではありません。 2)Pythonはデータサイエンスおよび機械学習ライブラリで強力ですが、JavaScriptはフロントエンド開発ライブラリとフレームワークで優れています。 3)どちらも豊富な学習リソースを持っていますが、Pythonは公式文書から始めるのに適していますが、JavaScriptはMDNWebDocsにより優れています。選択は、プロジェクトのニーズと個人的な関心に基づいている必要があります。

C/CからJavaScriptへ:すべてがどのように機能するかC/CからJavaScriptへ:すべてがどのように機能するかApr 14, 2025 am 12:05 AM

C/CからJavaScriptへのシフトには、動的なタイピング、ゴミ収集、非同期プログラミングへの適応が必要です。 1)C/Cは、手動メモリ管理を必要とする静的に型付けられた言語であり、JavaScriptは動的に型付けされ、ごみ収集が自動的に処理されます。 2)C/Cはマシンコードにコンパイルする必要がありますが、JavaScriptは解釈言語です。 3)JavaScriptは、閉鎖、プロトタイプチェーン、約束などの概念を導入します。これにより、柔軟性と非同期プログラミング機能が向上します。

JavaScriptエンジン:実装の比較JavaScriptエンジン:実装の比較Apr 13, 2025 am 12:05 AM

さまざまなJavaScriptエンジンは、各エンジンの実装原則と最適化戦略が異なるため、JavaScriptコードを解析および実行するときに異なる効果をもたらします。 1。語彙分析:ソースコードを語彙ユニットに変換します。 2。文法分析:抽象的な構文ツリーを生成します。 3。最適化とコンパイル:JITコンパイラを介してマシンコードを生成します。 4。実行:マシンコードを実行します。 V8エンジンはインスタントコンピレーションと非表示クラスを通じて最適化され、Spidermonkeyはタイプ推論システムを使用して、同じコードで異なるパフォーマンスパフォーマンスをもたらします。

ブラウザを超えて:現実世界のJavaScriptブラウザを超えて:現実世界のJavaScriptApr 12, 2025 am 12:06 AM

現実世界におけるJavaScriptのアプリケーションには、サーバー側のプログラミング、モバイルアプリケーション開発、モノのインターネット制御が含まれます。 2。モバイルアプリケーションの開発は、ReactNativeを通じて実行され、クロスプラットフォームの展開をサポートします。 3.ハードウェアの相互作用に適したJohnny-Fiveライブラリを介したIoTデバイス制御に使用されます。

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強力な PHP 統合開発環境

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

mPDF

mPDF

mPDF は、UTF-8 でエンコードされた HTML から PDF ファイルを生成できる PHP ライブラリです。オリジナルの作者である Ian Back は、Web サイトから「オンザフライ」で PDF ファイルを出力し、さまざまな言語を処理するために mPDF を作成しました。 HTML2FPDF などのオリジナルのスクリプトよりも遅く、Unicode フォントを使用すると生成されるファイルが大きくなりますが、CSS スタイルなどをサポートし、多くの機能強化が施されています。 RTL (アラビア語とヘブライ語) や CJK (中国語、日本語、韓国語) を含むほぼすべての言語をサポートします。ネストされたブロックレベル要素 (P、DIV など) をサポートします。

EditPlus 中国語クラック版

EditPlus 中国語クラック版

サイズが小さく、構文の強調表示、コード プロンプト機能はサポートされていません

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール