web-dev-qa-db-ja.com

Require.jsとDOMで<script>要素を作成するだけの違いは何ですか?

Require.JS AMDを使用して、DOMに_<script>_要素を作成するだけの違いは何ですか?

Require.JSの私の理解は、依存関係をロードする機能を提供することですが、必要な外部JSファイルをロードする_<script>_要素を作成するだけではこれを実行できないのですか?

たとえば、関数doStuff()を必要とするneedMe()があるとします。 doStuff()は外部ファイル_do_stuff.js_にあり、needMe()は外部ファイル_need_me.js_にあります。

Require.JSの方法でこれを行う:

_define(['need_me'],function(){
    function doStuff(){
        //do some stuff
        needMe();
        //do some more stuff
    }
});
_

スクリプト要素を作成するだけでこれを行います:

_function doStuff(){
    var scriptElement  = document.createElement('script');
    scriptElement.src = 'need_me.js';
    scriptElement.type = 'text/javascript';
    document.getElementsByTagName('head')[0].appendChild(scriptElement);

    //do some stuff
    needMe();
    //do some more stuff
}
_

これらは両方とも機能します。ただし、2番目のバージョンでは、Require.jsライブラリをすべて読み込む必要はありません。機能的な違いはあまりありません...

138
maxedison

Ajaxian.comで使用する理由に関するNice記事を次に示します。

RequireJS:非同期JavaScriptロード

  • ある種の#include/import/require
  • ネストされた依存関係をロードする機能
  • 開発者にとって使いやすいが、展開を支援する最適化ツールに支えられている
43
Sarfraz

DOMに要素を作成するだけの場合と比べて、Require.JSにはどのような利点がありますか?

この例では、スクリプトタグを非同期で作成しています。つまり、needMe()関数が呼び出されますbefore need_me.jsファイルの読み込みが完了します。これにより、関数が定義されていないキャッチされない例外が発生します。

代わりに、提案していることを実際に機能させるには、次のようなことをする必要があります。

function doStuff(){
    var scriptElement  = document.createElement('script');
    scriptElement.src = 'need_me.js';
    scriptElement.type = 'text/javascript';

    scriptElement.addEventListener("load", 
        function() { 
            console.log("script loaded - now it's safe to use it!");

            // do some stuff
            needMe();
            //do some more stuff

        }, false);

    document.getElementsByTagName('head')[0].appendChild(scriptElement);

}

おそらく、RequireJSなどのパッケージマネージャーを使用するか、上記のように純粋なJavaScript戦略を使用するのが最善である場合とそうでない場合があります。 Webアプリケーションの読み込みは高速になりますが、サイトでの機能の呼び出しは、そのアクションを実行する前にリソースの読み込みを待機する必要があるため、遅くなります。

Webアプリケーションが単一ページのアプリとして構築されている場合、人々が実際にページを頻繁にリロードすることはないと考えてください。これらの場合、すべてをプリロードすることで、実際にsingアプリを使用しているときのエクスペリエンスが速く見えるようになります。これらの場合、あなたは正しいです。ページのヘッドまたはボディにスクリプトタグを含めるだけで、すべてのリソースをロードできます。

ただし、ページからページに移行する従来のモデルに従ってWebサイトまたはWebアプリケーションを構築し、リソースを再ロードする場合、遅延ロードのアプローチがこれらの移行のスピードアップに役立つ場合があります。

52
jmort253

RequireJSを使用することが理にかなっている他のいくつかの非常に指摘された理由:

  1. 独自の依存関係の管理は、大規模なプロジェクトでは急速にばらばらになります。
  2. 必要な数の小さなファイルを作成でき、依存関係や読み込み順序を追跡することを心配する必要はありません。
  3. RequireJSを使用すると、ウィンドウオブジェクトに触れることなく、モジュラーアプリ全体を作成できます。

このGistでのrmurpheyのコメント から取得。

抽象化の層は、学習して調整するのは悪夢かもしれませんが、目的を果たしてうまく機能するとき、それは理にかなっています。

9

以下に、より具体的な例を示します。

私は60個のファイルがあるプロジェクトで働いています。実行には2つの異なるモードがあります。

  1. 連結バージョンの1つの大きなファイルをロードします。 (製造)

  2. 60個すべてのファイルをロード(開発)

ローダーを使用しているため、ウェブページにスクリプトが1つだけあります

_<script src="loader.js"></script>
_

デフォルトはmode#1(1つの大きな連結ファイルをロードする)です。 mode#2(個別のファイル)で実行するには、いくつかのフラグを設定します。それは何でもかまいません。クエリ文字列のキー。この例では、これを行うだけです

_<script>useDebugVersion = true;</script>
<script src="loader.js"></script>
_

loader.jsは次のようになります

_if (useDebugVersion) {
   injectScript("app.js");
   injectScript("somelib.js");
   injectScript("someotherlib.js");
   injectScript("anotherlib.js");
   ... repeat for 60 files ...
} else {
   injectScript("large-concatinated.js");
}
_

ビルドスクリプトは、次のような.shファイルです。

_cat > large-concantinated.js app.js somelib.js someotherlib.js anotherlib.js
_

等...

新しいファイルを追加する場合、開発を行っているため、mode#2を使用している可能性があります。loader.jsにinjectScript("somenewfile.js")行を追加する必要があります

その後、実稼働のために、ビルドスクリプトにsomenewfile.jsを追加する必要があります。よく忘れてエラーメッセージが表示されるステップ。

AMDに切り替えることで、2つのファイルを編集する必要がなくなります。 loader.jsとビルドスクリプトの同期を維持する問題はなくなります。 _r.js_またはwebpackを使用すると、コードを読み取って_large-concantinated.js_をビルドできます。

また、依存関係も処理できます。たとえば、次のようにlib1.jsとlib2.jsの2つのファイルをロードしました

_injectScript("lib1.js");
injectScript("lib2.js");
_

lib2にはlib1が必要です。内部には次のようなコードがあります

_lib1Api.installPlugin(...);
_

ただし、挿入されたスクリプトは非同期にロードされるため、正しい順序でロードされる保証はありません。これらの2つのスクリプトはAMDスクリプトではありませんが、require.jsを使用して依存関係を伝えることができます

_require.config({
    paths: {
        lib1: './path/to/lib1',
        lib2: './path/to/lib2',
    },
    shim: {
        lib1: {
            "exports": 'lib1Api',
        },
        lib2: {
            "deps": ["lib1"],
        },
    }
});
_

Lib1を使用するモジュールは、これを行います

_define(['lib1'], function(lib1Api) {
   lib1Api.doSomething(...);
});
_

Require.jsがスクリプトを挿入し、lib2がlib1に依存することを伝えたため、lib1がロードされるまでlib2を挿入しません。また、lib2とlib1の両方がロードされるまで、lib1を使用するモジュールは起動しません。

これにより、開発がニースになり(ビルド手順もロード順序の心配もなくなります)、生産がニースになります(追加されたスクリプトごとにビルドスクリプトを更新する必要がなくなります)。

追加のボーナスとして、webpackのbabelプラグインを使用して、古いブラウザーのコードでbabelを実行できます。この場合も、そのビルドスクリプトを維持する必要はありません。

Chrome(選択したブラウザ)が実際にimportのサポートを開始した場合、おそらく開発用に切り替えますが、実際には何も変わらないことに注意してください。 webpackを使用して連結ファイルを作成すると、すべてのブラウザのコードに対してbabelを実行できます。

これはすべて、スクリプトタグを使用せずにAMDを使用することで得られます。

0
gman