この記事は、WeChat ミニ プログラムのデュアル スレッド モデルを理解するのに役立ちます。ミニ プログラムのデュアル スレッド モデルとは何ですか?アプレットがブラウザのスレッド モデルを使用せず、デュアル スレッド モデルを使用するのはなぜですか? 皆さんのお役に立てれば幸いです。
WeChat アプレット開発の経験がある友人なら、「デュアル スレッド モデル」の概念を知っているはずです。この記事では、デュアル スレッド モデルに関する一般的な科学知識を簡単にまとめます。 . 知識が浅いので、間違いがあればご指摘ください。
私は以前「ミニ プログラム·クラウド開発」チームで働いていましたが、外部の研修や技術共有の場でよく次のような質問を受けました。「WeChat ミニ プログラムと Web サイトの主な技術的な違いは何ですか?」プログラミング言語とパラダイムの観点から見ると、小規模なプログラム開発は Web フロントエンド開発と非常によく似ています (たとえば、どちらも JavaScript 言語、HTML/CSS によく似た WXML/WXSS などを使用します)。ネイティブ フロントエンド テクノロジを直接使用しません。 [関連する学習の推奨事項: 小さなプログラム開発チュートリアル ]
Web Web サイトと比較して、WeChat でホストされる小規模なプログラムは、セキュリティ、パフォーマンス、その他の要素を考慮する必要があります。ミニ プログラムは、WeChat アプリ自体にセキュリティ リスクをもたらすことはなく、同時に、ネイティブ アプリケーションにできるだけ近いパフォーマンスとユーザー エクスペリエンスを実現しようとします。これらは、小さなプログラムがブラウザのスレッド モデルを直接使用せず、独自にデュアル スレッド モデルを構築する必要がある主な 2 つの理由です。
それでは、小規模プログラムのデュアル スレッド モデルとは何でしょうか?
新しい概念やテクノロジを理解するための最良の方法は、リファレンスを提供することです。したがって、小さなプログラムのスレッド モデルを理解するには、まずブラウザのスレッド モデルをある程度理解する必要があります。 。
おそらく、すべてのフロントエンド エンジニアは、最初に業界に入ったときに面接官から「フロントエンドの単一スレッドをどのように理解していますか?」と何度か尋ねられたことがあります。スキルの一つであるJavaScript言語はシングルスレッドです。JSシングルスレッドの動作を完全に理解し、使いこなすことは、フロントエンドエンジニアにとって最も基本的な要件です。しかし、多くの初心者が陥りやすい誤解があります。それは、「JavaScript シングルスレッド」を「ブラウザ シングルスレッド」と誤って理解することです。
実際、ブラウザの内部アーキテクチャは非常に複雑ですが、相互排他的でブロッキングな管理モデルを使用して、GUI レンダリング スレッドと JavaScript ロジック スクリプト スレッドを処理します。開発者は混乱し、誤解されています。
Chrome ブラウザを例に挙げると、右上隅にある設定ボタンをクリックし、「その他のツール」→「タスク マネージャー」と入力すると、次のようなポップアップ ウィンドウが表示されます。
Chrome がブラウザ プロセス、ネットワーク プロセス、GPU プロセスなどを含む複数のプロセスを開いていることがわかります。これらはすべて一般的なプロセスです。 注意してください, 上の図には 2 つのタブ プロセスがあります。Chrome はタブ ページごとに独立したレンダリング プロセス (レンダラー プロセス) を開き、各プロセス間のリソース (CPU、メモリなど) と動作を開きます。 (UI、ロジックなど) は相互に共有されないため、1 つのタブがクラッシュしても、他のタブには影響しません。
各タブ プロセスでは、ブラウザはさまざまなタスクを対応するスレッドに渡します。たとえば、GUI レンダリング スレッドは HTML をビジュアル UI にレンダリングする役割を果たし、JavaScript エンジン スレッドは解析と実行を担当します。 JavaScript コード。ロジック。タイミング トリガー スレッドは、setTimeout/setInterval タイマーなどの処理を担当します。
もう 1 つ、混乱しやすい場所があります。実際、setTimeout/setInterval は JavaScript 言語の一部ではなく、ランタイム (元々はブラウザー、後にノード) です。 .js もサポートしています) の機能を提供します。
GUI レンダリング スレッドと JavaScript エンジン スレッドは相互に排他的です。JavaScript は実行中に UI のレンダリングをブロックします。スクリプトの実行時間が長すぎる場合でも、ページはしばらく応答しなくなります。 GUI レンダリング スレッドと JavaScript エンジン スレッド間のこの相互排他的でブロック的なスレッド管理方法により、フロントエンド開発者の中にはブラウザがシングルスレッドであると考える人もいます。
では、なぜ JavaScript はシングルスレッドになるように設計されているのでしょうか?
JavaScript の創始者は、この言語を作成するのに 10 日しかかかりませんでした。彼の当初のアイデアは、ユーザー インタラクションや DOM 操作などを処理するために、ブラウザーにいくつかの単純なスクリプト ロジックを提供することでした。
構文は単純です;
操作メカニズムは単純です。
構文の点では、JavaScript は Java から借用していますが、型宣言やモジュール システム (後で追加) などの多くの複雑な設定が削除されています。
実行メカニズムに関して、JavaScript は Java のようなマルチスレッド機能を提供しません。主な理由は、マルチスレッドの DOM 操作によって引き起こされる UI の競合を回避するためです。たとえば、複数のスレッドが同じ DOM を同時に操作する場合、ブラウザは最終的な UI 効果を生成するためにどのスレッドが使用されるかをどのように決定すればよいでしょうか?これは古典的なスレッド セーフティ (スレッド同期とも呼ばれます) の問題です。マルチスレッド プログラミングの分野には、ロック メカニズムの追加など、多くの解決策がありますが、これはシンプルで使いやすい設計とは異なり、より複雑になります。 JavaScript の本来の意図に反します。
これは、GUI レンダリング スレッドと JavaScript エンジン スレッドが相互に排他的である理由も説明しています。JavaScript コードには、DOM を変更する権限があります。
JavaScript コードが実行されると、GUI レンダリング スレッドは一時停止され、JavaScript エンジン スレッドがアイドル状態になるまで待機してから実行されます。これにより、レンダリング中に JavaScript による DOM の繰り返し変更によって引き起こされる不要なレンダリングのプレッシャーが回避されます。相互排他モードを使用して JavaScript コードの実行が完了するのを待機すると、レンダリングが最終的な実行結果になるようにできます。したがって、ブラウザのアイドル時間も、Web サイトのパフォーマンスを測定するための重要な指標の 1 つになっています。アイドル時間は主に、JavaScript ロジックが集中的ではなく、DOM 変更の頻度が低いことを示します。この場合、ブラウザはユーザー インタラクションに応答できます。
#React Fiber はアイドル時間を使用してシャーディング タスクを処理します。
その後、HTML5 では、複数のスレッドで JavaScript コードを実行できる機能を提供する Web ワーカーが導入されました。ただし、他のプログラミング言語とは異なり、ワーカー スレッドはメイン スレッドと並列ではなく、メイン スレッドです。 . スレーブ (マスター/スレーブ) マルチスレッド モデル。
ワーカー内の JavaScript コードは DOM を操作できないため、スレッドセーフとして理解できます。 これは、後で説明する小規模プログラムのデュアル スレッド モデルの重要な基礎であることを覚えておいてください。
では、なぜ WeChat アプレットはブラウザのスレッド モデルを直接使用しないのでしょうか?そのためには、ミニ プログラムと Web サイトの違いを製品と技術の両方の観点から比較する必要があります。
私が初めてミニ プログラム開発に触れたとき、Web と比較して機能が弱いことがよく「嫌い」でした。単純にVueと比較したり、過剰な文法など。当時、私はミニ プログラムが WeChat の膨大なユーザー数に依存した技術独占であると感じていました。
しかし、技術や製品を深く理解し続けるにつれて、ミニプログラムに対する私の態度も「嫌い」から「賞賛」に変わりました。なぜなら、ミニプログラムの製品ポジショニングを十分に理解した後、 デュアル スレッド モデルは、小規模プログラムなどの製品シナリオにおける最適なソリューション です。では、ミニプログラムとはどのような製品なのでしょうか?
ミニ プログラムのホストは WeChat ですが、ミニ プログラムのバージョンの反復は独立しており、アップグレードや更新はホストに依存せず、これは Web ウェブサイトと同じです。言い換えれば、ミニ プログラムは Web の利点の一部を継承していますが、Web ではありません。現在、Web 関連テクノロジは非常に包括的であり、3D マップ、ゲームなどの非常に大規模なアプリケーションをホストできます。
ミニプログラムは、小さく、美しく、使い終わったら消えるという位置づけであり、WeChat の Web 機能をすべて追求しているわけではないため、Web に比べて性能的には明らかに劣ります。同時に、WeChat によって提供されるネイティブ機能の一部 (ネイティブ コンポーネント、システム レベル、WeChat エコシステム API など) も備えています。
また、「ミニプログラム-WeChat」の関係は「ウェブサイト-ブラウザ」の関係とは異なり、前者のほうがCodePenやJSFiddlerなどのオンラインプログラミングプラットフォームにおける各プログラムのケースに近いです(参考) as platform in class) (ケースと呼びます) とプラットフォームの関係。
技術的な観点から見ると、プラットフォームの中心的な考慮事項の 1 つは、ケースに十分な機能を提供することです。 ケースのロジックがプラットフォームのセキュリティを危険にさらさないようにするためです。 。 CodePen 上で CodePen の個人情報を取得するプログラムを作成できたら、おそらく次の日 CodePen がクラッシュして従業員全員が解雇されることを想像してください。
このようなプロダクトトーンの下でテクノロジーの選択が行われると、次のステップはアーキテクトとプログラマーの作業になります。
CodePen を例に挙げますが、そのようなプログラミング プラットフォームの設計を依頼された場合、どのようなテクノロジを使用しますか? iframe 内ですべての Web 機能を使用できるため、最初に iframe を使用することを考えるかもしれません。実際、CodePen はプログラム効果を表現するために iframe を使用しますが、入力された JavaScript コードを実行のために iframe に完全にコピーするわけではなく、コードは iframe に挿入される前にコンパイル プロセスを経ます。この開始点は主にセキュリティ上の考慮事項に基づいており、コンパイル プロセス中にいくつかの危険なコードを削除します。次に、これにより、プラットフォームで typescript などのより多くの言語をサポートすることもできます。もちろんパフォーマンスの問題もありますが、パフォーマンスの問題は iframe に関する一般的な問題なので、詳細については説明しません。
したがって、iframe を使用する必要があるだけでなく、追加の JavaScript コンパイラーを導入する必要もあります。 CodePen は、それぞれのケースで JavaScript コードがスレッドセーフであることを確認する必要があります。最も基本的なことは、プログラムが CodePen Web サイトの DOM を操作することを禁止することです。これを実現するには 2 つの方法があります:
1 つは Web Worker;
もう 1 つは Shadow DOM を使用することです。
Web Worker はスレッドセーフです。Worker 内の JavaScript コードは Window オブジェクトと Document オブジェクトを取得できないため、DOM を操作できません。さらに、ワーカーのスレッド セーフ機能により、ワーカー内のコードは実行中に外部の GUI レンダリング スレッドをブロックせず、これら 2 つは並行して実行できます。
Shadow DOM は Web コンポーネント仕様の一部です。ShadowRoot のモードを closed
に設定すると、ShadowRoot ノードが取得できなくなり、内部 DOM を操作できなくなります。
この 2 つと比較すると、Shadow DOM の互換性は Web Worker よりも悪く、大規模な利用の時期にはまだ遠いため、Web Worker ソリューションの方が現実的です。
これは単純な 2 スレッド モデルを形成します。ワーカー スレッドは計算を担当し、結果を postMessage を通じてメイン スレッドに渡し、メイン スレッドはレンダリングを担当します。
ただし、このモデルには深刻なパフォーマンスの問題があります。Web ワーカーは非常にリソースを消費します。コンピューティングの消費に加えて、メインスレッドとの通信プロセスにも非常に深刻な問題があります。パフォーマンスへの影響。
では、パフォーマンスを考慮し、優れたユーザー エクスペリエンスを確保しながら、Web Worker と同じスレッド セーフを実現する方法はあるのでしょうか?これが、WeChat アプレットにデュアル スレッド モデルを使用する主な目的です。
先ほど CodePen などのプログラミング プラットフォームを例えとして使用しましたが、小規模プログラムと CodePen の技術要件はまったく同じではありません。主な違いは次のとおりです。すべての HTML タグをサポートし、限られた数の UI コンポーネントのみを提供する必要がある ミニ プログラムの製品位置付けに従って、ミニ プログラムの主な技術要件を次のように要約できます。 (新しいテクノロジやアーキテクチャは、特定の問題を解決するように設計されているため、アプレットの主な技術要件を理解する必要があります。)
UI コンポーネント タイプを制限して、許可するもののみを指定します。指定する宣言
アプレットは、コンポーネントの宣言時にネイティブ HTML タグを使用しませんが、WeChat が提供するいくつかの組み込みの基本コンポーネントのみを使用できます。もちろん、コンポーネントをカスタマイズすることもできます, しかし、それは、組み込みの基本コンポーネントの組み合わせによっても実現されます。
論理スレッドの安全性を確保し、UI コンポーネントの直接操作を許可しない
ミニ プログラムが UI を更新する方法は、 Vue/React などの MVVM フレームワークでは、JavaScript コードで DOM を直接操作することはできませんが (ちなみに、実際にはアプレットに DOM の概念はありません)、状態を更新する (setState) ことで UI を非同期に更新します。 VDOM と効率的な diff アルゴリズムが使用されます (この 2 つの点は私たちが議論したいことではありません。関連する情報は授業後に検索できます)。
WeChat に依存せずにオンラインで更新可能
ミニ プログラムのホストは WeChat であり、純粋なネイティブを使用して実装されている場合は、ミニ プログラムのバージョンが更新されます。WeChat に依存して、WeChat コードとともにバージョンをリリースする必要がありますが、これは絶対に不可能です。純粋な Web 実装の場合、セキュリティとパフォーマンスを保証するのは困難です。
ミニ プログラムは、Web などのクラウドでリソースをホストし、独立して更新できる必要があると同時に、十分なセキュリティとパフォーマンスを確保できる必要があります。したがって、最終的に、アプレットは混合アーキテクチャ モデルを採用しました: Webview を使用して UI をレンダリングし、Web ワーカーと同様の独立したスレッドを使用してロジックを実行します。これはデュアル スレッド モデルです。
ユーザー エクスペリエンスを確保するには、パフォーマンスを可能な限り改善する必要があります。
シンプルなデュアル スレッド モデル ベースのパフォーマンス大きな問題は、ミニ プログラムのデュアル スレッド モデルが Web Worker のサブスレッドではなく、独立した「メイン スレッド」を使用するため、比較的良好なパフォーマンスが保証されることです。イベントドリブンの通信方式
上図のレンダリングスレッドとロジックスレッド間の通信方式に注目してください。 、アプレット レンダリング層とロジック層の間の通信は、両者の間でデータやイベントを直接転送しませんが、は仲介者としてネイティブによって転送されます。
プロセス全体は典型的なイベント駆動型モデルです:
レンダリング層 (ビュー層とも呼ばれます) は、インタラクションを通じて特定のイベントをトリガーします。イベント;
イベントはロジック層に渡されます;
ロジック層は一連のロジック処理を渡します、データ リクエスト、インターフェイスの呼び出しやその他のアクションにより、処理されたデータがレンダリング レイヤに渡されます。
#最終レンダリング レイヤは、データをビジュアル UI にレンダリングします。
このデータ駆動型 UI モデルは、現在、フロントエンド プログラミングの分野でより尊敬されているプログラミング パラダイムです。5 年以上の開発経験を持つフロントエンド開発者であれば、 , それから、このモデルに触れるとき、最初は多少の違和感があるはずだと思います。なぜなら、これ以前は、DOM の JavaScript 操作はほぼ「業界のルール」だったからです。入門用の本、ブログ、教科書もたくさんあります。 DOM 操作から始まるフロントエンドですが、今では確かに少し時代遅れになっているようです。
ロジックとレンダリングを分離するこのスレッド分割モードにより、論理スレッド サンドボックスで実行される JavaScript コードがスレッドセーフであることが保証される一方で、レンダリング スレッドの計算量が増加するため、が非常に小さいため、ユーザー インタラクション動作に対する迅速な応答によりユーザー エクスペリエンスが向上します。
一般に、ブラウザのスレッド モデルと比較して、ミニ プログラムのデュアル スレッド モデルは、Web ワーカーと同じスレッド セーフを実現しながら、Web ワーカーの懸念されるパフォーマンスを解決または回避します。パフォーマンスとセキュリティの両方の観点から。 デュアル スレッド モードは、ブラウザの既存のプロセスとスレッド管理モデルによって制限される小規模プログラムの特定のシナリオ内で改善されたアーキテクチャ ソリューションであると要約できます。
私の意見では、プログラマーの中核的な能力と競争力は、特定の言語やフレームワークの API を完全に理解することではなく、これらの言語の基礎となる原則を知ることであり、フレームワーク。小規模なプログラム開発者にとって、仕事で技術的な問題が発生したときの解決策は、多くの場合、基礎となる原則に基づいています (さらに単純に言えば、就職面接を探しているときに、小規模なプログラムの構文について質問する人は誰もいません)。
ミニ プログラムのデュアル スレッド モデルの背景、設計、通信を理解することで、皆さんがミニ プログラムの基礎となるアーキテクチャをより深く理解できることを願っています。後続の作業で同様のシナリオが必要な場合。もちろん、小規模プログラムのデュアル スレッド モデルを理解することが唯一の目標ではありません。この知識は、主にパフォーマンスの観点から、ある程度、日常の開発作業にインスピレーションを与えることができます。 ##機能性確保を前提にシンプルな構造のUIを使用することを心がける;
JavaScriptロジックの複雑さを軽減することを心がける;
setData 呼び出しの頻度と移植性を減らして、データ量を減らすようにしてください。
プログラミング関連の知識について詳しくは、
プログラミング ビデオ以上がミニプログラムでのデュアルスレッドモデルの詳細な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。