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ファイルに依存している場合があるためです。
前もって感謝します。
getScript()
でpromiseを使用して、すべてのスクリプトがロードされるまで待つことができます。
$.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
});
上記のコードでは、Deferredを追加して$()
内で解決することは、jQuery呼び出し内に$(func)
のような他の関数を配置することに似ています。
$(function() { func(); });
つまり、DOMの準備が整うまで待機するため、上記の例では$.when
はすべてのスクリプトがロードされるのを待機しますand DOM readyコールバックで解決される$.Deferred
呼び出しのために準備ができている.
スクリプトの配列を受け入れるユーティリティ関数は、次のように作成できます。
$.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
});
複数のスクリプトを並行してロードする単純な関数を実装しました。
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...
});
特定の順序でスクリプトをロードする必要がある場合があります。たとえば、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>
両方のキューのスクリプトは並行してダウンロードされますが、各キューのスクリプトは順番にダウンロードされるため、実行が順序どおりに行われます。ウォーターフォールチャート:
次のような必要なスクリプトを前のスクリプトのコールバックにロードします。
$.getScript('scripta.js', function()
{
$.getScript('scriptb.js', function()
{
// run script that depends on scripta.js and scriptb.js
});
});
yepnope.js または Modernizr (yepnope.jsをModernizr.load
として含む)を使用します。
UPDATE
ただフォローアップするために、yepnopeを使用している現在のものと同等のものを以下に示します。複数のスクリプトへの依存関係を示しています。
yepnope({
load: ['script1.js', 'script2.js', 'script3.js'],
complete: function () {
// all the scripts have loaded, do whatever you want here
}
});
クロスドメインが完全に正常に動作するAjaxによって正常にロードされた後、実際に実行されていない同じドメインのホットロードスクリプト(少なくともChromeで)を含む1つの問題を引き起こすマルチスクリプトロードで多くの問題に遭遇しました! :(
元の質問に対する選択された回答が確実に機能しません。
ここで多くの反復が行われた後、getScript(s)に対する最終的な答えがあり、jQuery 2.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(非推奨になりましたか?)を使用して見つけたのと同じで、試用版のWhen、Success&Completeは100%信頼できない!?、したがって、この機能とstatusCodeの使用などがあります。
必要に応じて、エラー/障害処理の動作を追加できます。
素晴らしい答え、アデネオ。
回答をより一般的なものにする方法を理解するのに少し時間がかかりました(コード定義のスクリプトの配列を読み込むことができるように)。すべてのスクリプトが読み込まれて実行されると、コールバックが呼び出されます。私の解決策は次のとおりです。
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();
}
});
}
次の機能を試すことで、$.when
-メソッドを利用できます。
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の使用方法であり、オーバーヘッドを最小限に抑えます。
探しているのは、AMD準拠のローダー(require.jsなど)です。
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);
}
これは私のために働く:
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(){
...
});
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
が呼び出されます。
JQueryのgetScriptメソッドを拡張するプラグインがあります。非同期および同期ロードを可能にし、jQueryのキャッシュメカニズムを使用します。完全な開示、私はこれを書いた。より良い方法を見つけたら、気軽に貢献してください。
上記の@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);
再帰を使用してこれを試してみることができます。これにより、リスト全体のダウンロードが完了するまで、同期して次々にダウンロードされます。
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();
});
}
上記のAndrew Marc Newtonの包括的な回答の短いバージョン。これはステータスコードの成功をチェックしません。未定義のUIの動作を避けるために行うべきです。
これは、jQueryを保証することはできますが、他には含まれない迷惑なシステムのためのものでした。そのため、外部スクリプトに強制された場合に外部スクリプトに追い込まれないほど短い技術が必要でした。 (インデックス0を最初の「再帰的」呼び出しに渡すことでさらに短くすることができますが、スタイルの習慣の力により砂糖が追加されました)。
また、依存関係リストをモジュール名に割り当てているため、このブロックは「module1」が必要な場所に含めることができ、スクリプトと依存する初期化は1回のみ含まれます/実行されます(コールバックにindex
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);
}
別の、しかし非常にシンプルなアプローチがあります。複数のスクリプトをロードするには、それらを本文に追加するだけです。
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);
});
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')});