もう一つ? なんで? CommonJSとAMDはありますか? 被害者は猫の下に行くことができます。
モジュールやモジュール式システムがなぜ必要なのかについては説明しませんが、これに関する記事があり
ます azproductionからの
JavaScriptモジュールのパス 、私たちは
要点に直行します。 結局のところ、すでにCommonJSとAMDがあります。 しかし、どちらにも欠点が1つあります。私が参加するほとんどのプロジェクトでは、致命的ではないとしても、非常に不便です。何らかの形で多かれ少なかれ同期しています。 そして、この欠点を回避するために松葉杖を思いついて書く必要がある状況がしばしばありました。
簡単な例を考えてみましょう。モジュール
moduleA 、
moduleB 、
moduleCがあり、後者は前の2つのモジュールに依存しています。
まず、これら3つのモジュールすべて(CommonJS、AMD、YM)のモジュールを説明するコードを記述します。
Commonjs
moduleA.js:module.exports = 'A';
moduleB.js: module.exports = 'B';
moduleC.js: var moduleA = require('A'), moduleB = require('B'); module.exports = moduleA + moduleB + 'C';
接続と使用:
var moduleC = require('C'); console.log(moduleC);
AMD
moduleA.js: define('A', function() { return 'A'; });
moduleB.js: define('B', function() { return 'B'; });
moduleC.js: define('', ['A', 'B'], function(moduleA, moduleB) { return moduleA + moduleB + 'C'; });
接続と使用:
require([''], function(moduleC) { console.log(moduleC);
うん
moduleA.js: modules.define('A', function(provide) { provide('A'); });
moduleB.js: modules.define('B', function(provide) { provide('B'); });
moduleC.js: modules.define('C', ['A', 'B'], function(provide, moduleA, moduleB) { provide(moduleA + moduleB + 'C'); });
接続と使用:
modules.require([''], function(moduleC) { console.log(moduleC);
これまでのところ興味深いものはありません。 3つの例はすべて同等です。 ここで、YMモジュールの1つの詳細に注意してください。特定の
提供関数がモジュール宣言のコールバック関数に渡されます。 なぜそこにあるのかは特にわかりにくいですが、モジュール
CommonAと
moduleBがすぐに(CommonJSとAMDが必要とするように)同期を
とることができず、そのために何らかの非同期アクションを実行する必要がある状況を想像してください。 簡単にするために、
setTimeout
ます。 YMを使用すると、前の例を次のように簡単に書き換えることができます(CommonJSまたはAMDを使用して表現することはできませんが、後者にはタイトルに
非同期という単語が含まれていますが、宣言メソッドとモジュールの再取得メソッドにのみ影響します):
moduleA.js: modules.define('A', function(provide) { setTimeout(function() { provide('A'); }); });
moduleB.js: modules.define('B', function(provide) { setTimeout(function() { provide('B'); }); });
moduleC.js: modules.define('C', ['A', 'B'], function(provide, moduleA, moduleB) { provide(moduleA + moduleB + 'C'); });
同時に、
moduleC自体は
moduleAと
moduleBの非同期性について何も知らないことに注意してください。 利益
人生の例
合成例から実際の例に移ります。 プロジェクトでは、Yandex.Maps APIを使用します。これは、原則として、同期的にロードできません(内部ではマルチステージロードを使用します)。 これは、おおよそ、書くだけでは不可能であり、その後のすべてのスクリプトが完成したAPIで動作することを期待することを意味します。 開始するには、
ymaps.ready
イベントを待つ必要があります。 私たちのプロジェクトは非常に複雑で、apiの基本クラスからの多くの継承を使用します。 それらの1つの例を考えてみましょう。 独自のcomplexLayerレイヤークラスがあり、これをymapsのベースレイヤーymaps.Layerから継承します。 YMでは、これは単純に行われます。APIをロードし、目的のイベント(ymaps.ready)を待機してから自身を提供するymapsモジュールを定義します。 APIモジュール(ymap)に依存するすべてのモジュールは、その後のみ解決を開始します。 したがって、私たちのモジュールは、Yandex.Maps APIの非同期性については何も知りません。 コードに松葉杖はありません!
ymaps.js:
modules.define( 'ymaps', ['loader', 'config'], function(provide, loader, config) { loader(config.hosts.ymaps + '/2.1.4/?lang=ru-RU&load=package.full&coordorder=longlat', function() { ymaps.ready(function() { provide(ymaps); }); }); });
ローダーと
設定モジュールのコードはここでは示しません。最初のコードはURLでスクリプトをロードでき、2番目のコードは定数のハッシュです。
ComplexLayer.js:
modules.define('ComplexLayer', ['inherit', 'ymaps'], function(provide, inherit, ymaps) { var ComplexLayer = inherit(ymaps.Layer, ...); provide(ComplexLayer); });
たとえば、jQueryに依存する必要がある場合もまったく同じです。
jqueryモジュールを定義します。
modules.define( 'jquery', ['loader', function(provide, loader) { loader('//yandex.st/jquery/2.1.0/jquery.min.js', function() { provide(jQuery.noConflict(true)); }); });
そして、他のすべてのモジュールで
jqueryモジュールの依存関係を使用します。
したがって、プロジェクトのコード全体はモジュールのみであり、グローバリティはなく、他のスクリプト(サードパーティのスクリプトを含む)または他のモジュールを接続する手順についての合意はなく、非同期性については松葉杖はありません。
結論として、YMモジュラーシステムのAPIを提供します(実際、さらにいくつかのメソッドがありますが、ここでは主要なメソッドのみを示します)。
モジュール宣言
void modules.define( String moduleName, [String[] dependencies], Function( Function(Object objectToProvide) provide, [Object resolvedDependency, ...], [Object previousDeclaration] ) declarationFunction )
モジュール接続
void modules.require( String[] dependencies, Function( [Object resolvedDependency, ...] ) callbackFunction )
プロジェクトリポジトリ:
github.com/ymaps/modules