[ES6] Ruan Yifeng ES6 学習モジュールのロード実装

1. ブラウザの読み込み

伝統的な手法

HTML Web ページでは、ブラウザは<script>タグを通じて JavaScript スクリプトを読み込みます。

<!-- 页面内嵌的脚本 -->
<script type="application/javascript">
  // module code
</script>

<!-- 外部脚本 -->
<script type="application/javascript" src="path/to/myModule.js">
</script>

デフォルトでは、ブラウザは JavaScript スクリプトを同期的に読み込みます。つまり、レンダリング エンジンは<script>タグに遭遇すると停止し、スクリプトが実行されるまで待機し、その後レンダリングを続けます。外部スクリプトの場合は、スクリプトのダウンロード時間も追加する必要があります。スクリプトのサイズが大きい場合、ダウンロードと実行に時間がかかるため、ブラウザがブロックされ、ユーザーはブラウザが応答せずに「スタック」しているように感じます。ユーザーエクスペリエンスは非常に悪いです。

そのため、ブラウザではスクリプトを非同期的に読み込むことができます。非同期読み込み用の 2 つの構文を次に示します。

<script src="path/to/myModule.js" defer></script>
<script src="path/to/myModule.js" async></script>

deferまたはasync属性を指定すると、スクリプトは非同期でロードされます。レンダリング エンジンは、このコマンド行を検出すると、外部スクリプトのダウンロードを開始しますが、ダウンロードして実行されるのを待たずに、次のコマンドを直接実行します。

deferとのasync違い

  • deferページ全体がメモリ内で正常にレンダリングされるまで (DOM 構造が完全に生成され、他のスクリプトが実行されるまで) 実行されません。

  • asyncダウンロードが完了すると、レンダリング エンジンはレンダリングを中断し、このスクリプトの実行後にレンダリングを続行します。

要約する: 「レンダリング後に実行」と「ダウンロード後に実行」deferです。asyncまた、複数のスクリプトがある場合defer、ページに表示される順序で読み込まれますが、複数のasyncスクリプトは読み込み順序を保証できません。

ロードルール

ブラウザはES6モジュールをロードします。このモジュールでも<script>タグが使用されますが、type="module"属性が追加されます。

<script type="module" src="./foo.js"></script>

ES6 モジュールでは Web ページに埋め込むこともでき、構文と動作は外部スクリプトを読み込む場合とまったく同じです。

<script type="module">
  import utils from "./utils.js";

  // other code
</script>

予防:

  • コードはグローバル スコープではなくモジュール スコープで実行されます。モジュール内のトップレベル変数。外部には表示されません。
  • モジュール スクリプトは、宣言されているかどうかに関係なく、厳密モードを自動的に採用しますuse strict
  • モジュール間では、importコマンドを使用して他のモジュールをロードできます (.jsサフィックスは省略できません。絶対 URL または相対 URL を指定する必要があります)。また、exportコマンドを使用して外部インターフェイスを出力することもできます。
  • モジュール内では、トップレベルのthisキーワードは を指すundefinedのではなく、 を返しますwindowつまり、モジュールの最上位で this キーワードを使用しても意味がありません。
  • 同じモジュールが複数回ロードされた場合、実行されるのは 1 回だけです。

ES6 モジュールと CommonJS モジュールの違い

1. CommonJS モジュールは値のコピーを出力しますが、ES6 モジュールは値への参照を出力します。

// lib.js
var counter = 3;
function incCounter() {
    
    
  counter++;
}
module.exports = {
    
    
  counter: counter,
  incCounter: incCounter,
};
// main.js
var mod = require('./lib');

console.log(mod.counter);  // 3
mod.incCounter();
console.log(mod.counter); // 3
// lib.js
var counter = 3;
function incCounter() {
    
    
  counter++;
}
module.exports = {
    
    
  get counter() {
    
    
    return counter
  },
  incCounter: incCounter,
};

2. CommonJS モジュールは実行時にロードされ、ES6 モジュールはコンパイル時に出力インターフェイスになります。

3. CommonJS モジュールの require() はモジュールを同期的にロードし、ES6 モジュールの import コマンドは非同期的にロードします。また、モジュールの依存関係の独立した解析フェーズがあります。

3. Node.jsモジュールの読み込み方法

JavaScript には現在 2 種類のモジュールがあります。1 つはES6module (省略形)でESM、もう 1 つはCommonJSmodule (省略形)ですCJS

CommonJSこのモジュールはNode.js独自仕様であり、ES6モジュールと互換性がありません。文法に加えて、この 2 つの最も明らかな違いは、CommonJSモジュールではrequire()and が使用されmodule.exportsES6モジュールではimportandが使用されることですexport

Node.jsモジュールが接尾辞のファイル名ES6を取得する必要があります。.mjsつまり、スクリプト ファイル内でimportまたはコマンドが使用されている限りexport、サフィックス名を使用する必要があります.mjsNode.js がファイルを検出すると.mjs、それが ES6 モジュールであると見なされます。厳密モードはデフォルトで有効になっており、各モジュール ファイルの先頭で指定する必要はありません"use strict"

サフィックス名を に変更したくない場合は、.mjsプロジェクトファイルのようにフィールドpackage.jsonを指定できますtypemodule

{
    
    
   "type": "module"
}

設定すると、プロジェクトの JS スクリプトは ES6 モジュールとして解釈されます。

# 解释成 ES6 模块
$ node my-app.js

現時点で CommonJS モジュールを使用したい場合は、CommonJS スクリプトのサフィックス名を に変更する必要があります.cjsフィールドがない場合type、またはtypeフィールドが の場合commonjs、.js スクリプトはCommonJSモジュールとして解釈されます。

要約する:.mjsファイルは常に ES6 モジュールとしてロードされ、ファイルは常にモジュール.cjsとしてCommonJSロードされ、.jsファイルのロードはpackage.json内のフィールドの設定によって異なりますtype

CommonJS モジュールは ES6 モジュールをロードします

CommonJSrequire()コマンドは ES6 モジュールをロードできず、エラーが報告されるため、import()このメソッドは ES6 モジュールをロードする場合にのみ使用できます。

// 在 CommonJS 模块中运行
(async () => {
    
    
  await import('./my-app.mjs');
})();

require()ES6 モジュールがサポートされない理由の 1 つは、ES6 モジュールが同期的にロードされ、トップレベルのコマンドが ES6 モジュール内で使用できるためawait、同期的にロードできないことです。

ES6 モジュールは CommonJS モジュールをロードします

ES6 モジュールimportコマンドはモジュールをロードできますCommonJSが、単一の出力項目だけではなく全体としてのみロードできます。

// 正确
import packageMain from 'commonjs-package';

// 报错
import {
    
     method } from 'commonjs-package';

これは、ES6 モジュールは静的コード分析をサポートする必要があるのに対し、CommonJS モジュールの出力インターフェイスはmodule.exports静的分析できないオブジェクトであるため、全体としてのみロードできるためです。

単一の出力項目をロードするには、次のように記述できます。

import packageMain from 'commonjs-package';
const {
    
     method } = packageMain;

Node.js の組み込みmodule.createRequire()メソッドを使用する別の読み込み方法もあります。

// cjs.cjs
module.exports = 'cjs';

// esm.mjs
import {
    
     createRequire } from 'module';

const require = createRequire(import.meta.url);

const cjs = require('./cjs.cjs');
cjs === 'cjs'; // true

上記のコードでは、ES6 モジュールはメソッドを通じてモジュールmodule.createRequire()をロードできます。CommonJSただし、この書き方はES6と をCommonJS混ぜることに相当するため、使用はお勧めしません。

おすすめ

転載: blog.csdn.net/Bon_nenul/article/details/128317499