検索
ホームページウェブフロントエンドjsチュートリアルJavaScriptモジュールの循環ロードの実装方法_JavaScriptスキル

「循環依存関係」とは、スクリプト a の実行はスクリプト b に依存し、スクリプト b の実行はスクリプト a に依存することを意味します。

// a.js
var b = require('b');

// b.js
var a = require('a');

通常、「ループ読み込み」は強い結合が存在することを示します。適切に処理しないと、再帰読み込みが発生してプログラムが実行できなくなる可能性があるため、回避する必要があります。

しかし実際には、これを避けるのは難しく、特に複雑な依存関係を持つ大規模なプロジェクトでは、a が b に依存し、b が c に依存し、c が a に依存することが容易になります。これは、モジュール読み込みメカニズムが「ループ読み込み」状況を考慮する必要があることを意味します。

この記事では、JavaScript 言語が「ループ読み込み」を処理する方法を紹介します。現在、最も一般的な 2 つのモジュール形式である CommonJS と ES6 は、処理方法が異なり、異なる結果を返します。

1. CommonJS モジュールの読み込み原理

ES6 が「ループ読み込み」をどのように処理するかを紹介する前に、まず最も一般的な CommonJS モジュール形式の読み込み原理を紹介しましょう。

CommonJSのモジュールはスクリプトファイルです。 require コマンドが初めてスクリプトをロードするとき、スクリプト全体が実行され、メモリ内にオブジェクトが生成されます。

{
 id: '...',
 exports: { ... },
 loaded: true,
 ...
}

上記のコードでは、オブジェクトの id 属性はモジュール名、exports 属性はモジュールによって出力される各インターフェイス、loaded 属性はモジュールのスクリプトが実行されたかどうかを示すブール値です。他にもたくさんの属性がありますが、ここでは省略します。 (詳細な導入については、「require() ソース コードの解釈」を参照してください。)

今後このモジュールを使用する必要がある場合は、exports 属性から値を取得します。 requireコマンドを再度実行しても、モジュールは再度実行されませんが、値はキャッシュから取得されます。

2. CommonJS モジュールのループ読み込み

CommonJS モジュールの重要な機能は、ロード時の実行です。つまり、すべてのスクリプト コードが必要に応じて実行されます。 CommonJS のアプローチは、モジュールが「ループロード」されると、実行された部分のみが出力され、未実行の部分は出力されないというものです。

公式ドキュメントの例を見てみましょう。スクリプトファイルa.jsのコードは以下のとおりです。

exports.done = false;
var b = require('./b.js');
console.log('在 a.js 之中,b.done = %j', b.done);
exports.done = true;
console.log('a.js 执行完毕');

上記のコードでは、a.js スクリプトは最初に Done 変数を出力し、次に別のスクリプト ファイル b.js を読み込みます。この時点で a.js コードはここで停止し、b.js の実行が完了するのを待ってから実行を続行することに注意してください。

b.js コードをもう一度見てください。

exports.done = false;
var a = require('./a.js');
console.log('在 b.js 之中,a.done = %j', a.done);
exports.done = true;
console.log('b.js 执行完毕');

上記のコードでは、b.jsを2行目まで実行すると、a.jsが読み込まれます。このとき「ループロード」が発生します。システムは、a.js モジュールに対応するオブジェクトの exports 属性の値を取得します。ただし、a.js はまだ実行されていないため、exports 属性から取得できるのは実行された部分だけであり、最終的な値は取得できません。

a.js の実行部分は 1 行だけです。


exports.done = false;


したがって、b.js の場合、a.js から行われた変数を 1 つだけ入力し、値は false になります。

その後、b.js は実行を継続し、すべての実行が完了すると、実行権が a.js に戻ります。したがって、a.js は実行が完了するまで実行を続けます。このプロセスを検証するスクリプト main.js を作成します。

var a = require('./a.js');
var b = require('./b.js');
console.log('在 main.js 之中, a.done=%j, b.done=%j', a.done, b.done);

main.jsを実行すると以下のようになります。

$ node main.js

在 b.js 之中,a.done = false
b.js 执行完毕
在 a.js 之中,b.done = true
a.js 执行完毕
在 main.js 之中, a.done=true, b.done=true

上記のコードは 2 つのことを証明しています。まず、b.jsではa.jsは実行されておらず、最初の行だけが実行されています。次に、main.js を 2 行目まで実行すると、再び b.js が実行されるのではなく、キャッシュされた b.js の実行結果、つまり 4 行目が出力されます。

exports.done = true;

3. ES6 モジュールのループロード

ES6 モジュールの動作メカニズムは CommonJS とは異なります。モジュール読み込みコマンドのインポートに遭遇した場合、モジュールは実行されず、参照が生成されるだけです。本当に使用する必要があるまで待ってから、モジュール内の値を取得します。

したがって、ES6 モジュールは動的参照であり、値のキャッシュの問題はなく、モジュール内の変数は、それらが配置されているモジュールにバインドされます。以下の例を参照してください。

// m1.js
export var foo = 'bar';
setTimeout(() => foo = 'baz', 500);

// m2.js
import {foo} from './m1.js';
console.log(foo);
setTimeout(() => console.log(foo), 500);

上記のコードでは、最初にロードされたとき、m1.js の変数 foo は bar と等しくなりますが、500 ミリ秒後には再び baz と等しくなります。

m2.js がこの変更を正しく読み取れるかどうかを確認してみましょう。

$ babel-node m2.js

bar
baz

上記のコードは、ES6 モジュールが実行結果をキャッシュせず、ロードされたモジュールの値を動的に取得し、変数が常にその変数が配置されているモジュールにバインドされていることを示しています。

これにより、ES6 は CommonJS とは本質的に異なる方法で「ループ読み込み」を処理します。 ES6 は「ループ読み込み」が発生するかどうかをまったく気にせず、ロードされたモジュールへの参照を生成するだけです。開発者は、値が実際に取得されるときにその値が取得できることを確認する必要があります。

次の例を参照してください (Axel Rauschmayer 博士による「Exploring ES6」からの抜粋)。

// a.js
import {bar} from './b.js';
export function foo() {
 bar(); 
 console.log('执行完毕');
}
foo();

// b.js
import {foo} from './a.js';
export function bar() { 
 if (Math.random() > 0.5) {
 foo();
 }
}

按照CommonJS规范,上面的代码是没法执行的。a先加载b,然后b又加载a,这时a还没有任何执行结果,所以输出结果为null,即对于b.js来说,变量foo的值等于null,后面的foo()就会报错。

但是,ES6可以执行上面的代码。

$ babel-node a.js

执行完毕

a.js之所以能够执行,原因就在于ES6加载的变量,都是动态引用其所在的模块。只要引用是存在的,代码就能执行。

我们再来看ES6模块加载器SystemJS给出的一个例子。

// even.js
import { odd } from './odd'
export var counter = 0;
export function even(n) {
 counter++;
 return n == 0 || odd(n - 1);
}

// odd.js
import { even } from './even';
export function odd(n) {
 return n != 0 && even(n - 1);
}

上面代码中,even.js里面的函数foo有一个参数n,只要不等于0,就会减去1,传入加载的odd()。odd.js也会做类似操作。

运行上面这段代码,结果如下。

$ babel-node
> import * as m from './even.js';
> m.even(10);
true
> m.counter
6
> m.even(20)
true
> m.counter
17

上面代码中,参数n从10变为0的过程中,foo()一共会执行6次,所以变量counter等于6。第二次调用even()时,参数n从20变为0,foo()一共会执行11次,加上前面的6次,所以变量counter等于17。

这个例子要是改写成CommonJS,就根本无法执行,会报错。

// even.js
var odd = require('./odd');
var counter = 0;
exports.counter = counter;
exports.even = function(n) {
 counter++;
 return n == 0 || odd(n - 1);
}

// odd.js
var even = require('./even').even;
module.exports = function(n) {
 return n != 0 && even(n - 1);
}

上面代码中,even.js加载odd.js,而odd.js又去加载even.js,形成"循环加载"。这时,执行引擎就会输出even.js已经执行的部分(不存在任何结果),所以在odd.js之中,变量even等于null,等到后面调用even(n-1)就会报错。

$ node
> var m = require('./even');
> m.even(10)
TypeError: even is not a function

[说明] 本文是我写的《ECMAScript 6入门》第20章《Module》中的一节。

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
JavaScriptの文字列文字を交換しますJavaScriptの文字列文字を交換しますMar 11, 2025 am 12:07 AM

JavaScript文字列置換法とFAQの詳細な説明 この記事では、javaScriptの文字列文字を置き換える2つの方法について説明します:内部JavaScriptコードとWebページの内部HTML。 JavaScriptコード内の文字列を交換します 最も直接的な方法は、置換()メソッドを使用することです。 str = str.replace( "find"、 "置換"); この方法は、最初の一致のみを置き換えます。すべての一致を置き換えるには、正規表現を使用して、グローバルフラグGを追加します。 str = str.replace(/fi

独自のJavaScriptライブラリを作成および公開するにはどうすればよいですか?独自のJavaScriptライブラリを作成および公開するにはどうすればよいですか?Mar 18, 2025 pm 03:12 PM

記事では、JavaScriptライブラリの作成、公開、および維持について説明し、計画、開発、テスト、ドキュメント、およびプロモーション戦略に焦点を当てています。

ブラウザでのパフォーマンスのためにJavaScriptコードを最適化するにはどうすればよいですか?ブラウザでのパフォーマンスのためにJavaScriptコードを最適化するにはどうすればよいですか?Mar 18, 2025 pm 03:14 PM

この記事では、ブラウザでJavaScriptのパフォーマンスを最適化するための戦略について説明し、実行時間の短縮、ページの負荷速度への影響を最小限に抑えることに焦点を当てています。

ブラウザ開発者ツールを使用してJavaScriptコードを効果的にデバッグするにはどうすればよいですか?ブラウザ開発者ツールを使用してJavaScriptコードを効果的にデバッグするにはどうすればよいですか?Mar 18, 2025 pm 03:16 PM

この記事では、ブラウザ開発者ツールを使用した効果的なJavaScriptデバッグについて説明し、ブレークポイントの設定、コンソールの使用、パフォーマンスの分析に焦点を当てています。

jQueryマトリックス効果jQueryマトリックス効果Mar 10, 2025 am 12:52 AM

マトリックスの映画効果をあなたのページにもたらしましょう!これは、有名な映画「The Matrix」に基づいたクールなJQueryプラグインです。プラグインは、映画の古典的な緑色のキャラクター効果をシミュレートし、画像を選択するだけで、プラグインはそれを数値文字で満たされたマトリックススタイルの画像に変換します。来て、それを試してみてください、それはとても面白いです! それがどのように機能するか プラグインは画像をキャンバスにロードし、ピクセルと色の値を読み取ります。 data = ctx.getimagedata(x、y、settings.greasize、settings.greasize).data プラグインは、写真の長方形の領域を巧みに読み取り、jQueryを使用して各領域の平均色を計算します。次に、使用します

シンプルなjQueryスライダーを構築する方法シンプルなjQueryスライダーを構築する方法Mar 11, 2025 am 12:19 AM

この記事では、jQueryライブラリを使用してシンプルな画像カルーセルを作成するように導きます。 jQuery上に構築されたBXSLiderライブラリを使用し、カルーセルをセットアップするために多くの構成オプションを提供します。 今日、絵のカルーセルはウェブサイトで必須の機能になっています - 1つの写真は千の言葉よりも優れています! 画像カルーセルを使用することを決定した後、次の質問はそれを作成する方法です。まず、高品質の高解像度の写真を収集する必要があります。 次に、HTMLとJavaScriptコードを使用して画像カルーセルを作成する必要があります。ウェブ上には、さまざまな方法でカルーセルを作成するのに役立つ多くのライブラリがあります。オープンソースBXSLiderライブラリを使用します。 BXSLiderライブラリはレスポンシブデザインをサポートしているため、このライブラリで構築されたカルーセルは任意のものに適合させることができます

JavaScriptによる構造マークアップの強化JavaScriptによる構造マークアップの強化Mar 10, 2025 am 12:18 AM

キーポイントJavaScriptを使用した構造的なタグ付けの強化は、ファイルサイズを削減しながら、Webページコンテンツのアクセシビリティと保守性を大幅に向上させることができます。 JavaScriptを効果的に使用して、Cite属性を使用して参照リンクを自動的にブロック参照に挿入するなど、HTML要素に機能を動的に追加できます。 JavaScriptを構造化されたタグと統合することで、ページの更新を必要としないタブパネルなどの動的なユーザーインターフェイスを作成できます。 JavaScriptの強化がWebページの基本的な機能を妨げないようにすることが重要です。 高度なJavaScriptテクノロジーを使用できます(

Angularを使用してCSVファイルをアップロードおよびダウンロードする方法Angularを使用してCSVファイルをアップロードおよびダウンロードする方法Mar 10, 2025 am 01:01 AM

データセットは、APIモデルとさまざまなビジネスプロセスの構築に非常に不可欠です。これが、CSVのインポートとエクスポートが頻繁に必要な機能である理由です。このチュートリアルでは、Angular内でCSVファイルをダウンロードおよびインポートする方法を学びます

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ヘンタイを無料で生成します。

ホットツール

WebStorm Mac版

WebStorm Mac版

便利なJavaScript開発ツール

Dreamweaver Mac版

Dreamweaver Mac版

ビジュアル Web 開発ツール

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser は、オンライン試験を安全に受験するための安全なブラウザ環境です。このソフトウェアは、あらゆるコンピュータを安全なワークステーションに変えます。あらゆるユーティリティへのアクセスを制御し、学生が無許可のリソースを使用するのを防ぎます。

VSCode Windows 64 ビットのダウンロード

VSCode Windows 64 ビットのダウンロード

Microsoft によって発売された無料で強力な IDE エディター

メモ帳++7.3.1

メモ帳++7.3.1

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