はじめに
これは ES6 ノートの最後のコンテンツで、唯一将来のみ使用可能な特性です
将来とはいつでしょうか?
おそらく HTTP2 が普及する時でしょう。しかし、より可能性が高いのは将来も「使用できない」(やはりビルドツールでのみ使用可能で、「コンパイル期」にのみ存在する)ことです
一.AMD、CMD と CommonJS
AMD/CMD、少しの拡張知識は以下の通り:
CommonJS は一整套の理論規範(例えば js の理論規範は ES)で、SeaJS、RequireJS はすべて CommonJS の Modules 部分の具体的実装です
CommonJS はブラウザ外(server 端)向けの js に対して制定されたもので、同期モジュールロードです。SeaJS は CommonJS の 1 つの実装で、RequireJS も CommonJS の 1 つの実装ですが、非同期モジュールロードで、ブラウザのシングルスレッド環境により贴近しています
まとめ:CommonJS の Modules 部分はモジュール化コード管理の理論を提出し、js をモジュール化ロードできるようにしました。RequireJS、SeaJS などの各種実装はモジュール化スクリプトローダーと呼べます
CMD:Common モジュール定義、例えば SeaJS
AMD:非同期モジュール定義、例えば RequireJS
すべてコードモジュールを定義する一整套の規範で、モジュール化スクリプトロードに便利で、応答速度を向上
CMD と AMD の違い:
CMD は依存を就近に。使用に便利で、モジュール内部で随時随所に取得でき、事前に依存項目を声明する必要がないため、性能面で若干の低下があります(モジュール全体を走査して依存項目を探す必要があります)
AMD は依存を前置に。厳格に依存項目を声明する必要があり、ロジック内部の依存項目(軟依存)に対しては、非同期ロード、コールバック処理の方式で解決します
([JS プログラミング常識](/articles/js プログラミング常識/#articleHeader9) から引用)
JS モジュール化に関心があれば、この 3 つの混乱した関係を清楚にしているはずです。ES6 モジュールは標準を通じてこの混乱を終結させることを希望しています
二.ES6 モジュール構文
1.モジュール作用域
module はモジュール作用域を導入し、特徴は以下の通り:
-
現在(
2016/1/312016/10/29)ブラウザは ES6 モジュールをサポートしていません(おそらくこのようなモジュールロードメカニズムはブラウザ環境に適さない)、webpack などのツールを利用して import のすべての内容を 1 つのファイルに統合できます -
ES6 モジュールはデフォルトで厳密モードで、
'use strict';を追加するかどうかにかかわらず -
導入/导出時にリネームをサポート、
import/export {api as newApi}、導入時にリネームは主に命名衝突を解決し、导出時にリネームはエイリアス($とjQuery)を実現 -
デフォルト導入/导出をサポート、CommonJS と AMD モジュールを導入可能
-
import/exportを使用できるのはモジュールの最外層作用域のみで、条件文中で使用することはできません
まとめ:厳密モードを推進;CommonJS と AMD と互換;単なる静的モジュールメカニズムで、按需ロードなどの問題を解決していない
導入/导出時にリネーム、例は以下の通り:
// 導入時にリネーム、命名衝突を解決
import {flip as flipOmelet} from "eggs.js";
import {flip as flipHouse} from "real-estate.js";
// 导出時にリネーム、エイリアスを実現
function v1() { ... }
function v2() { ... }
export {
v1 as streamV1,
v2 as streamV2,
v2 as streamLatestVersion
};
2.import
import {api1, api2...} from 'xxx.js' 構文、特徴は以下の通り:
-
api 部分導入をサポート(必要のない機能インターフェースを導入しない、もちろん、
xxx.jsは完全にロードされ、部分導入は作用域制御のみ) -
xxx.jsにさらにimport文がある場合、深度優先でロード実行 -
実行済みモジュールは無視され、循環引用を形成するのを回避
-
デフォルト導入をサポート、CommonJS と AMD パッケージを導入するために使用(
defaultはexportオブジェクト)、import api from 'xxx.js'はimport {default as api} from 'xxx.js'と同等 -
モジュールオブジェクトの導入をサポート、
import * as apis from 'xxx.js'、*はxxx.js中のexportのすべてのものを表し、xxx.jsから导出されたすべてのものをapisオブジェクトに統合し、apis.xxを通じてアクセス
まとめ:ロードメカニズムは CSS の @import に類似、循環依存を処理する方式も類似;同样 CommonJS と AMD と互換
作用域レベルで部分導入をサポート、有用ですが、意義は大きくなく、ビルドツールと配合してコンパイル時に「剪枝」(tree shaking)する方がより良い
3.export
export {api1, api2...} 構文、特徴は以下の通り:
-
首行で声明する必要はなく、モジュール内外層作用域任意の位置で
export可能 -
複数の
exportを声明可能ですが、api 名称が重複しないことを保証する必要があり、名称が重複するとエラーが発生する可能性があります -
デフォルト导出をサポート、
export default apiまたはexport {api as default} -
聚合导出をサポート、
export {api1, api2...} from 'xxx.js'はimport + exportと同等ですが、export fromは当前モジュール作用域に各 api 変数を導入しません(導入後直接导出、引用不可) -
exportが导出する api リストはリテラル形式でなければならず、配列を走査して配列要素を导出することはできません
まとめ:ロード時に export リストを整理するため、外層任意の位置で export 可能;聚合をサポート、各第三者モジュールから一部を取り出して統合;静的制限、動的导出を許可しない
例は以下の通り:
// デフォルト导出
let myObject = {
field1: value1,
field2: value2
};
export {myObject as default};
// 同等
export default {
field1: value1,
field2: value2
};
// 聚合导出
// "sri-lanka" を導入し、それが导出した内容の一部を再导出
export {Tea, Cinnamon} from "sri-lanka";
// "equatorial-guinea" を導入し、それが导出した内容の一部を再导出
export {Coffee, Cocoa} from "equatorial-guinea";
// "singapore" を導入し、それが导出した内容のすべてを导出
export * from "singapore";
三.モジュール実行メカニズム
ES6 標準は具体的モジュールロードメカニズムを明記せず、最終実装に委ねますが、モジュール実行メカニズムを明確に規定し、4 つのステップに分かれます
- 構文解析
構文エラーをチェック
- ロード
すべての import されたものを再帰的にロード、具体的にどのようにロードするか、明記せず、完全に最終実装に委ね
- 接続
モジュール作用域を作成し、すべての import されたものを作用域に塞ぎ込み
import がエラーの場合、エラーをトリガー、具体的行為は未知(まだブラウザが第 2 歩を歩んだことがないため)
- ランタイム
各モジュールのすべての文を実行、この時 import/export に遭遇すれば無視、モジュール関連の処理はすでに終了しているため
静的制限
-
import/exportを使用できるのはモジュール最外層作用域のみで、条件文中で使用することはできず、関数作用域でも使用できません -
exportの識別子はリテラル形式でなければならず(ソースコード中に対応する声明がある)、配列を走査して一連のものを导出することはできません -
モジュールオブジェクトは凍結され、モジュールオブジェクトを
hackしてpolyfillスタイルの新特性を追加することはできません -
モジュールのすべての依存はモジュールコード実行前にロード、解析され接続完了する必要があり、
importを通じて按需懶ロードする構文は存在しません -
importモジュールが生成するエラーには対応する回復メカニズムがありません。あるモジュールがロードまたは接続できない場合、すべてのモジュールは実行されず、importエラーをキャッチできません -
モジュールが依存をロードする前に他のコードを実行することはできず、これはモジュールの依存ロードプロセスを制御できないことを意味します
これらの制限が存在するため、おそらくHTTP2 が普及した後でも、ES6 モジュールメカニズムはやはりブラウザで興起できない可能性があります。CSS の @import のように、使用可能ですが、誰も使用したがらないのと同じです
四.HTTP2 とモジュール化
HTTP1.1 の環境下では、HTTP 請求数量を減少させるために、すべてのモジュール化方案は最終的にビルドツールに依存して単一ファイルを統合します
しかし HTTP2 はいくつかの変革をもたらし、おそらくこのエンジニアリングプロセスを変更できる可能性があります。例えば多路复用流(Multiplexed stream)とサーバー端プッシュ:
Http2 接続は数十または数百の流の复用を承载可能で、多路复用は多くの流からのデータパケットが混合されて同じ接続を通じて传输できることを意味し、2 列の異なる列車が混合されて传输され、終点に到達した時、それらはまた拆解されて 2 列の異なる列車を組成します。
クライアントがリソース X を請求し、サーバー端はクライアントがさらにリソース Z を必要とするかもしれないと判断し、事前にクライアントに詢問する必要なくリソース Z をクライアントにプッシュし、クライアントは受け取った後、キャッシュして後で使用するために備えます。
(Http 2.0 プロトコル简介 から引用)
多路复用流はファイル合併の優位性を抹平し、サーバー端プッシュは深度 import 問題を解決するのに役立つため、ES6 モジュールはブラウザ環境で興起する可能性があります
HTTP2 はモジュール化プロセスに対して重要な意義があり、生産環境でモジュール化を保持する機会を提供し、JS、CSS さらに他のリソースも真のモジュール化を迎える可能性があります
P.S. HTTP2 のより多くの詳細については、https://github.com/bagder/http2-explained を参照
五.ES6 モジュール現状
As the various milestones of the roadmap are completed, browsers will be able to implement them. See the following trackers for the current status of the main browsers:
IE/Edge: Under Consideration
Firefox: In progress
Chrome: In progress
Webkit: Meta Bug
(https://github.com/whatwg/loader から引用)
ES6 モジュールローダーに関するより多くの情報についてはこの repo を关注してください。ES6 規範はロードの具体的実装を説明していないため、ブラウザはすべてローダーの実装で卡っています
参考資料
- 『ES6 in Depth』:InfoQ 中文站が提供する無料電子書籍
コメントはまだありません