jQuery $ .getScript()メソッドを使用して複数のjsファイルを含める方法


127

JavaScriptファイルをjsファイルに動的に含めようとしています。私はそれについていくつかの調査を行い、jQuery $ .getScript()メソッドが望ましい方法であることを発見しました。

// jQuery
$.getScript('/path/to/imported/script.js', function()
{
    // script is now loaded and executed.
    // put your dependent JS here.
    // what if the JS code is dependent on multiple JS files? 
});

しかし、この方法で一度に複数のスクリプトをロードできるかどうか疑問に思っていますか?私がこれを尋ねているのは、私のJavaScriptファイルが複数のjsファイルに依存している場合があるためです。

前もって感謝します。

回答:


315

答えは

次のように、promiseを使用してgetScript()、すべてのスクリプトが読み込まれるまで待つことができます。

$.when(
    $.getScript( "/mypath/myscript1.js" ),
    $.getScript( "/mypath/myscript2.js" ),
    $.getScript( "/mypath/myscript3.js" ),
    $.Deferred(function( deferred ){
        $( deferred.resolve );
    })
).done(function(){
    
    //place your code here, the scripts are all loaded
    
});

FIDDLE

アナザーFIDDLE

上記のコードでは、Deferredを追加して内部で解決するの$()は、jQuery呼び出し内に他の関数を配置するようなものです$(func)

$(function() { func(); });

つまり、DOMが準備するためにそれはそう上記の例では、待機$.when待機すべてのスクリプトをロードするため DOMが原因で準備されるためには$.Deferred、DOM準備コールバックで解決さコール。


より一般的な使用のために、便利な機能

スクリプトの配列を受け入れるユーティリティ関数は、次のように作成できます。

$.getMultiScripts = function(arr, path) {
    var _arr = $.map(arr, function(scr) {
        return $.getScript( (path||"") + scr );
    });
        
    _arr.push($.Deferred(function( deferred ){
        $( deferred.resolve );
    }));
        
    return $.when.apply($, _arr);
}

このように使用できます

var script_arr = [
    'myscript1.js', 
    'myscript2.js', 
    'myscript3.js'
];

$.getMultiScripts(script_arr, '/mypath/').done(function() {
    // all scripts loaded
});

パスはすべてのスクリプトの先頭に追加されますが、これもオプションです。つまり、配列に完全なURLが含まれている場合は、これを行うこともでき、パスをすべて省略できます。

$.getMultiScripts(script_arr).done(function() { ...

引数、エラーなど

余談ですが、doneコールバックには、渡されたスクリプトと一致する多数の引数が含まれることに注意してください。各引数は、応答を含む配列を表します

$.getMultiScripts(script_arr).done(function(response1, response2, response3) { ...

各配列にはのようなものが含まれます[content_of_file_loaded, status, xhr_object]。スクリプトはとにかく自動的に読み込まれるので、通常、これらの引数にアクセスする必要はありません。ほとんどの場合、doneコールバックはすべてのスクリプトが読み込まれたことを知るために必要なすべてです。 、そしてロードされたファイルからの実際のテキストにアクセスする必要がある場合や、各XHRオブジェクトまたは類似のものにアクセスする必要がある場合はまれです。

また、いずれかのスクリプトがロードに失敗すると、失敗ハンドラーが呼び出され、後続のスクリプトはロードされません

$.getMultiScripts(script_arr).done(function() {
     // all done
}).fail(function(error) {
     // one or more scripts failed to load
}).always(function() {
     // always called, both on success and error
});

11
すばらしい答えをありがとう。$.Deferred(function( deferred ){$( deferred.resolve );})ここに追加する理由を教えていただけませんか?
ソジェン

11
延期されたオブジェクトは、複数のスクリプトをロードし、すべてが完了したときに機能を実行できるという約束とは実際には何の関係もありません。$()の準備ができているかどうかを確認し、準備ができているかどうかを解決します。つまり、document.readyのように、コードを実行する前にDOMの準備ができていることを確認し、アタッチの良い例を見つけましたコードで遅延DOM対応機能を備えたgetScriptをオンラインで提供することを約束し、それが良いアイデアのように聞こえるのでそれを保持することを決定しました。
adeneo

4
AJAXでのキャッシングはjQueryのではデフォルトでオフになっているためのが、オンにすると、クエリ文字列を削除やっていること:$.ajaxSetup({ cache: true });それはまた、あなたがキャッシュにしたくないことを他のAjaxの呼び出しに影響を与える可能性があり、多くは、よりこの上ありますのためのドキュメントgetScript、そしてcachedScriptと呼ばれるキャッシュされたgetScript関数を作成する方法も少しあります。
adeneo

3
遅くなって申し訳ありません。時々あなたの方法はまだ完全に機能していません。理由がわからない。一度に4つのスクリプトファイルを組み込もうとしています。$.when($.getScript(scriptSrc_1), $.getScript(scriptSrc_2), $.getScript(scriptSrc_3), $.getScript(scriptSrc_4), $.Deferred(function(deferred) { $(deferred.resolve); })).done(function() { ... })
ソジェン

1
これを機能させることができない場合は、JSファイルに解析エラーがないことを確認してください。つまり、最初に<script>タグで適切にロードされることをテストします。jQuery.getScript()はこれらのエラーをロードの失敗と見なし、.done()の代わりに.fail()が呼び出されます。@SongtaoZ。
ムーンプリズムパワー

29

複数のスクリプトを並列にロードする単純な関数を実装しました。

関数

function getScripts(scripts, callback) {
    var progress = 0;
    scripts.forEach(function(script) { 
        $.getScript(script, function () {
            if (++progress == scripts.length) callback();
        }); 
    });
}

使用法

getScripts(["script1.js", "script2.js"], function () {
    // do something...
});

1
何らかの理由で、これはエマニュエルのものよりもうまく機能しました。これも非常に透過的な実装です。
トッド14

@satnamありがとう:)!トップ回答が一部の人(私を含む)で機能しないため、このソリューションを投稿しました。そして、それははるかにシンプルに見えます。
Andrei

10

次のような必要なスクリプトを、前のスクリプトのコールバックにロードします。

$.getScript('scripta.js', function()
{
   $.getScript('scriptb.js', function()
   {
       // run script that depends on scripta.js and scriptb.js
   });
});

1
確かに、この方法ではスクリプトが順次ダウンロードされ、最終的な実行までの時間が遅くなりますか?
神保

1
正解、@ Jimbo-公平を期します。早期実行よりも望ましいです。:)
Alastair、2014

滝はほとんど常に避けられるべきです。getScriptにはpromiseが付属しています... $ .whenを使用して、promiseが解決されるタイミングを聞くことができます。
Roi

@Roiと他の誰か:特定の順序でスクリプトをロードする必要がある場合、基本的にこのアプローチの何が問題になっていますか?したがって、代替の約束にはどのような利点がありますか?
Ifedi Okonkwo 2016

@IfediOkonkwoこれは、シリーズにする必要がある場合に機能しますが、元の操作では、一度に複数を使用したいと述べました(この場合、これはアンチパターンになります)。それでも、それらを直列にしたい場合は、配列を渡すことができるループ関数を記述します。深い入れ子は乱雑になります。
Roi

9

スクリプトを特定の順序でロードする必要がある場合があります。たとえば、jQueryはjQuery UIの前にロードする必要があります。このページのほとんどの例では、スクリプトを並列に(非同期に)読み込みます。つまり、実行順序は保証されません。順序付けを行わないと、両方が正常にロードされたが順序が間違っているとy、依存するスクリプトxが壊れる可能性があります。

依存するスクリプトの逐次読み込み+オプションの並列読み込み+ 遅延オブジェクトを可能にするハイブリッドアプローチを提案します

/*
 * loads scripts one-by-one using recursion
 * returns jQuery.Deferred
 */
function loadScripts(scripts) {
  var deferred = jQuery.Deferred();

  function loadScript(i) {
    if (i < scripts.length) {
      jQuery.ajax({
        url: scripts[i],
        dataType: "script",
        cache: true,
        success: function() {
          loadScript(i + 1);
        }
      });
    } else {
      deferred.resolve();
    }
  }
  loadScript(0);

  return deferred;
}

/*
 * example using serial and parallel download together
 */

// queue #1 - jquery ui and jquery ui i18n files
var d1 = loadScripts([
  "https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/jquery-ui.min.js",
  "https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/i18n/jquery-ui-i18n.min.js"
]).done(function() {
  jQuery("#datepicker1").datepicker(jQuery.datepicker.regional.fr);
});

// queue #2 - jquery cycle2 plugin and tile effect plugin
var d2 = loadScripts([
  "https://cdn.rawgit.com/malsup/cycle2/2.1.6/build/jquery.cycle2.min.js",
  "https://cdn.rawgit.com/malsup/cycle2/2.1.6/build/plugin/jquery.cycle2.tile.min.js"

]).done(function() {
  jQuery("#slideshow1").cycle({
    fx: "tileBlind",
    log: false
  });
});

// trigger a callback when all queues are complete
jQuery.when(d1, d2).done(function() {
  console.log("All scripts loaded");
});
@import url("https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/blitzer/jquery-ui.min.css");

#slideshow1 {
  position: relative;
  z-index: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

<p><input id="datepicker1"></p>

<div id="slideshow1">
  <img src="https://dummyimage.com/300x100/FC0/000">
  <img src="https://dummyimage.com/300x100/0CF/000">
  <img src="https://dummyimage.com/300x100/CF0/000">
</div>

両方のキューのスクリプトは並行してダウンロードされますが、各キューのスクリプトは順番にダウンロードされるため、順序どおりに実行されます。ウォーターフォールチャート:

スクリプトのウォーターフォールチャート


スクリプトがメモリに読み込まれたら、HTMLにスクリプトタグを追加する必要はありませんか?
Ankush Jain

4

使用はyepnope.js又はModernizr(AS yepnope.jsを含みますModernizr.load)。

更新

補足として、複数のスクリプトへの依存関係を示す、yepnopeを現在使用しているものと同等のものを次に示します。

yepnope({
  load: ['script1.js', 'script2.js', 'script3.js'],
  complete: function () {
      // all the scripts have loaded, do whatever you want here
  }
});

ありがとう。HTMLファイルにタグをyepnope.injectJs( scriptSource )含めるのと同じように、JavaScriptファイルの先頭で複数を使用でき<script>ますか?
ソジェン

それは新しく、正直なところ、なぜそれが必要なのか理解できません。最近の変更のリストを少し過ぎてドキュメントをたどると、より一般的な使用法が表示されます。
Chris Pratt、

+1; これは、とは異なり、依存関係を適切に管理する(つまり、同じスクリプトを2回ロードしない)ことに注意してください$.getScript。これは大きな問題です。
2013

yepnope.jsは非推奨になりました
ステファン

4

Ajaxで正常に読み込まれた後、スクリプトの同じドメインのホットロードが実際に実行されない(少なくともChromeでは)1つの問題を含め、マルチスクリプトの読み込みでいくつかの問題が発生しました。:(

元の質問に対して選択した回答が確実に機能しません。

多くの反復の後、ここでは、getScript(s)に対する最終的な回答と、スクリプトごとにロードされるコールバックオプションと完了時の全体的なコールバックを使用して、複数のスクリプトを特定の厳密な順序で非同期にロードします。jQuery2.1以降と最新バージョンのChrome、Firefoxでテスト済み見捨てられたInternet Explorer。

私のテストケースは、THREE.JS webGLレンダーのファイルをロードし、onCompleteへの匿名関数呼び出しに渡された間隔チェックを使用してTHREEグローバルが利用可能になったときにレンダースクリプトを開始しました。

プロトタイプ関数(getScripts)

function getScripts( scripts, onScript, onComplete )
{
    this.async = true;
    this.cache = false;
    this.data = null;
    this.complete = function () { $.scriptHandler.loaded(); };
    this.scripts = scripts;
    this.onScript = onScript;
    this.onComplete = onComplete;
    this.total = scripts.length;
    this.progress = 0;
};

getScripts.prototype.fetch = function() {
    $.scriptHandler = this;
    var src = this.scripts[ this.progress ];
    console.log('%cFetching %s','color:#ffbc2e;', src);

    $.ajax({
        crossDomain:true,
        async:this.async,
        cache:this.cache,
        type:'GET',
        url: src,
        data:this.data,
        statusCode: {
            200: this.complete
        },
        dataType:'script'
    });
};

getScripts.prototype.loaded = function () {
    this.progress++;
    if( this.progress >= this.total ) {
        if(this.onComplete) this.onComplete();
    } else {
        this.fetch();
    };
    if(this.onScript) this.onScript();
};

使い方

var scripts = new getScripts(
    ['script1.js','script2.js','script.js'],
    function() {
        /* Optional - Executed each time a script has loaded (Use for Progress updates?) */
    },
    function () {
        /* Optional - Executed when the entire list of scripts has been loaded */
    }
);
scripts.fetch();

この関数は、Deferred(非推奨?

必要に応じて、エラー/失敗の処理動作を追加できます。


正しい順序でロードするための+1、多くの場合不可欠であり、何かが欠落していない限り、受け入れられた答えは保証しませんか?以下に同様の短い回答を掲載しましたが、これはより一般的なケースです。
Whelkaholism 14年

2

$.when次の関数を試して-method を利用できます。

function loadScripts(scripts) {
  scripts.forEach(function (item, i) {
    item = $.getScript(item);
  });
  return $.when.apply($, scripts);
}

この関数は次のように使用されます:

loadScripts(['path/to/script-a.js', 'path/to/script-b.js']).done(function (respA, respB) {
    // both scripts are loaded; do something funny
});

これがPromiseを使用する方法であり、オーバーヘッドを最小限に抑えます。


これにより、スクリプトが順番に読み込まれますか?
Cyber​​Monk 2014年

2

素晴らしい答え、アデネオ。

答えをより一般的なものにする方法を理解するのに少し時間がかかりました(コード定義のスクリプトの配列をロードできるようにするため)。すべてのスクリプトが読み込まれて実行されると、コールバックが呼び出されます。これが私の解決策です:

    function loadMultipleScripts(scripts, callback){
        var array = [];

        scripts.forEach(function(script){
            array.push($.getScript( script ))
        });

        array.push($.Deferred(function( deferred ){
                    $( deferred.resolve );
                }));

        $.when.apply($, array).done(function(){
                if (callback){
                    callback();
                }
            });
    }

2

async = falseでスクリプトを追加する

これは別の、しかし非常にシンプルなアプローチです。複数のスクリプトをロードするには、単にそれらを本文に追加します。

  • ブラウザーがページの読み込みを最適化する方法であるため、非同期で読み込みます
  • ブラウザーがHTMLタグを解析する方法であるため、スクリプトを順番に実行します
  • スクリプトは順番に実行されるため、コールバックは不要です。別のスクリプトを追加するだけで、他のスクリプトの後に実行されます

詳細はこちら:https : //www.html5rocks.com/en/tutorials/speed/script-loading/

var scriptsToLoad = [
   "script1.js", 
   "script2.js",
   "script3.js",
]; 
    
scriptsToLoad.forEach(function(src) {
  var script = document.createElement('script');
  script.src = src;
  script.async = false;
  document.body.appendChild(script);
});

1

探しているのは、AMD準拠のローダー(require.jsなど)です。

http://requirejs.org/

http://requirejs.org/docs/whyamd.html

調べてみると、多くの優れたオープンソースのものがあります。基本的に、これによりコードのモジュールを定義できます。他のコードモジュールに依存している場合は、それらのモジュールのダウンロードが完了するまで待機してから実行を開始します。この方法では、10個のモジュールを非同期でロードでき、実行するために他のいくつかのモジュールに依存している場合でも問題は発生しません。


1

この関数は、依存関係ファイルが完全に読み込まれた後にファイルが読み込まれるようにします。他のファイルへの依存関係を念頭に置いて、シーケンスでファイルを提供する必要があるだけです。

function loadFiles(files, fn) {
    if (!files.length) {
        files = [];
    }
    var head = document.head || document.getElementsByTagName('head')[0];

    function loadFile(index) {
        if (files.length > index) {
            var fileref = document.createElement('script');
            fileref.setAttribute("type", "text/javascript");
            fileref.setAttribute("src", files[index]);
            head.appendChild(fileref);
            index = index + 1;
            // Used to call a callback function
            fileref.onload = function () {
                loadFile(index);
            }
        } else if(fn){
            fn();
        }
    }
    loadFile(0);
}

ファイルを順番にロードするので、おそらく受け入れられた回答よりも良いでしょう。script2にscript1をロードする必要がある場合は、順序付けが不可欠です。
Salman A

1

これは私にとってはうまくいきます:

function getScripts(scripts) {
    var prArr = [];
    scripts.forEach(function(script) { 
        (function(script){
            prArr .push(new Promise(function(resolve){
                $.getScript(script, function () {
                    resolve();
                });
            }));
        })(script);
    });
    return Promise.all(prArr, function(){
        return true;
    });
}

そしてそれを使う:

var jsarr = ['script1.js','script2.js'];
getScripts(jsarr).then(function(){
...
});

1

これは、Maciej Sawickiのものを使用してPromise、コールバックとして実装する答えです。

function loadScripts(urls, path) {
    return new Promise(function(resolve) {
        urls.forEach(function(src, i) {

            let script = document.createElement('script');        
            script.type = 'text/javascript';
            script.src = (path || "") + src;
            script.async = false;

            // If last script, bind the callback event to resolve
            if(i == urls.length-1) {                    
                // Multiple binding for browser compatibility
                script.onreadystatechange = resolve;
                script.onload = resolve;
            }

            // Fire the loading
            document.body.appendChild(script);
        });
    });
}

使用する:

let JSDependencies = ["jquery.js",
                      "LibraryNeedingJquery.js",
                      "ParametersNeedingLibrary.js"];

loadScripts(JSDependencies,'JavaScript/').then(taskNeedingParameters);

すべてのJavaScriptファイルはできるだけ早くダウンロードされ、指定された順序で実行されます。次にtaskNeedingParameters呼び出されます。


0

上記のAndrew Marc Newtonの包括的な回答の短縮版。これはステータスコードの成功をチェックしません。これは、未定義のUI動作を回避するために実行する必要があります。

これは、jQueryは保証できるが他のインクルードは保証できない迷惑なシステム用でした。そのため、外部スクリプトに強制された場合に外部スクリプトに流用されないように十分に短い手法が必要でした。(最初の「再帰的」呼び出しにインデックス0を渡すことでさらに短くすることができますが、スタイルの習慣の影響で砂糖を追加しました)。

また、依存関係リストをモジュール名に割り当てているので、このブロックは「module1」が必要な任意の場所に含めることができ、スクリプトと依存する初期化は1回だけ含まれ、実行されます(indexコールバックにログインして、1つの順序が表示されるのを確認できます。実行中のAJAXリクエストのセット)

if(typeof(__loaders) == 'undefined') __loaders = {};

if(typeof(__loaders.module1) == 'undefined')
{
    __loaders.module1 = false;

    var dependencies = [];

    dependencies.push('/scripts/loadmefirst.js');
    dependencies.push('/scripts/loadmenext.js');
    dependencies.push('/scripts/loadmelast.js');

    var getScriptChain  = function(chain, index)        
    {
        if(typeof(index) == 'undefined')
            index = 0;

        $.getScript(chain[index], 
            function()
            {
                if(index == chain.length - 1)
                {
                    __loaders.module1 = true;

                    /* !!!
                        Do your initialization of dependent stuff here 
                    !!! */
                }
                else 
                    getScriptChain(chain, index + 1);
            }
        );
    };

    getScriptChain(dependencies);       
}

0

jQueryのgetScriptメソッドを拡張するプラグインがあります。非同期および同期の読み込みを可能にし、jQueryのキャッシュメカニズムを使用します。完全な開示、これを書いた。より良い方法を見つけたら、気軽に貢献してください。

https://github.com/hudsonfoo/jquery-getscripts


0

n個のスクリプトを1つずつロードします(たとえば、2番目のファイルに1番目のファイルが必要な場合に役立ちます)。

(function self(a,cb,i){
    i = i || 0; 
    cb = cb || function(){};    
    if(i==a.length)return cb();
    $.getScript(a[i++],self.bind(0,a,cb,i));                    
})(['list','of','script','urls'],function(){console.log('done')});

0

上記の@adeneoからの回答に基づく:cssファイルとjsファイルの両方のロードの組み合わせ

改善のための提案はありますか?

// Usage
//$.getMultiResources(['script-1.js','style-1.css'], 'assets/somePath/')
//  .done(function () {})
//  .fail(function (error) {})
//  .always(function () {});

(function ($) {
  $.getMultiResources = function (arr, pathOptional, cache) {
    cache = (typeof cache === 'undefined') ? true : cache;
    var _arr = $.map(arr, function (src) {
      var srcpath = (pathOptional || '') + src;
      if (/.css$/i.test(srcpath)) {
        return $.ajax({
          type: 'GET',
          url: srcpath,
          dataType: 'text',
          cache: cache,
          success: function () {
            $('<link>', {
              rel: 'stylesheet',
              type: 'text/css',
              'href': srcpath
            }).appendTo('head');
          }
        });

      } else {
        return $.ajax({
          type: 'GET',
          url: srcpath,
          dataType: 'script',
          cache: cache
        });
      }
    });
    //
    _arr.push($.Deferred(function (deferred) {
      $(deferred.resolve);
    }));
    //
    return $.when.apply($, _arr);
  };
})(jQuery);

0

再帰を使用してこれを試すことができます。これにより、リスト全体のダウンロードが完了するまで、同期して次々とダウンロードされます。

var queue = ['url/links/go/here'];

ProcessScripts(function() { // All done do what ever you want

}, 0);

function ProcessScripts(cb, index) {
    getScript(queue[index], function() {
        index++;
        if (index === queue.length) { // Reached the end
            cb();
        } else {
            return ProcessScripts(cb, index);
        }
    });
}

function getScript(script, callback) {
    $.getScript(script, function() {
        callback();
    });
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.