いくつかのプラグイン、カスタムウィジェット、JQueryのその他のライブラリを使用しています。その結果、いくつかの.jsファイルと.cssファイルがあります。読み込みに時間がかかるため、サイトのローダーを作成する必要があります。すべてをインポートする前にローダーを表示できるといいでしょう:
<script type="text/javascript" src="js/jquery-1.6.2.min.js"></script>
<script type="text/javascript" src="js/myFunctions.js"></script>
<link type="text/css" href="css/main.css" rel="stylesheet" />
...
....
etc
JavaScriptライブラリを非同期にインポートできるようにするチュートリアルをいくつか見つけました。たとえば、次のようなことができます:
(function () {
var s = document.createElement('script');
s.type = 'text/javascript';
s.async = true;
s.src = 'js/jquery-ui-1.8.16.custom.min.js';
var x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
})();
何らかの理由で、すべてのファイルに同じことをすると、ページは機能しません。私は問題がどこにあるのかを見つけようと長い間努力してきましたが、それを見つけることができません。まず、いくつかのjavascript関数が他の関数に依存しているためだと思いました。しかし、タイムアウト機能を使用して正しい順序でそれらをロードしました。たとえば、リンクなどをクリックすることはできません...アニメーションはまだ動作します。
これが私が考えていることです...ブラウザにはキャッシュがあると思います。そのため、初めてページをロードしてから次に高速にページをロードするのに長い時間がかかるのです。私が考えているのは、index.htmlページを、このすべてのファイルを非同期にロードするページに置き換えることです。 ajaxがすべてのファイルの読み込みを完了すると、使用する予定のページにリダイレクトされます。そのページを使用する場合、ファイルはブラウザのキャッシュに既に含まれている必要があるため、ロードに時間がかかりません。インデックスページ(.jsファイルと.cssファイルが非同期に読み込まれるページ)で、エラーが発生することは気にしません。ローダーを表示し、完了したらページをリダイレクトします...
このアイデアは良い選択肢ですか?または、非同期メソッドの実装を試行し続ける必要がありますか?
非同期のすべてをロードする方法は次のとおりです。
importScripts();
function importScripts()
{
//import: jquery-ui-1.8.16.custom.min.js
getContent("js/jquery-1.6.2.min.js",function (code) {
var s = document.createElement('script');
s.type = 'text/javascript';
//s.async = true;
s.innerHTML=code;
var x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
setTimeout(insertNext1,1);
});
//import: jquery-ui-1.8.16.custom.min.js
function insertNext1()
{
getContent("js/jquery-ui-1.8.16.custom.min.js",function (code) {
var s = document.createElement('script');
s.type = 'text/javascript';
s.innerHTML=code;
var x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
setTimeout(insertNext2,1);
});
}
//import: jquery-ui-1.8.16.custom.css
function insertNext2()
{
getContent("css/custom-theme/jquery-ui-1.8.16.custom.css",function (code) {
var s = document.createElement('link');
s.type = 'text/css';
s.rel ="stylesheet";
s.innerHTML=code;
var x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
setTimeout(insertNext3,1);
});
}
//import: main.css
function insertNext3()
{
getContent("css/main.css",function (code) {
var s = document.createElement('link');
s.type = 'text/css';
s.rel ="stylesheet";
s.innerHTML=code;
var x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
setTimeout(insertNext4,1);
});
}
//import: jquery.imgpreload.min.js
function insertNext4()
{
getContent("js/farinspace/jquery.imgpreload.min.js",function (code) {
var s = document.createElement('script');
s.type = 'text/javascript';
s.innerHTML=code;
var x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
setTimeout(insertNext5,1);
});
}
//import: Marquee.js
function insertNext5()
{
getContent("js/Marquee.js",function (code) {
var s = document.createElement('script');
s.type = 'text/javascript';
s.innerHTML=code;
var x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
setTimeout(insertNext6,1);
});
}
//import: Marquee.css
function insertNext6()
{
getContent("css/Marquee.css",function (code) {
var s = document.createElement('link');
s.type = 'text/css';
s.rel ="stylesheet";
s.innerHTML=code;
var x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
setTimeout(insertNext,1);
});
}
function insertNext()
{
setTimeout(pageReadyMan,10);
}
}
// get the content of url and pass that content to specified function
function getContent( url, callBackFunction )
{
// attempt to create the XMLHttpRequest and make the request
try
{
var asyncRequest; // variable to hold XMLHttpRequest object
asyncRequest = new XMLHttpRequest(); // create request object
// register event handler
asyncRequest.onreadystatechange = function(){
stateChange(asyncRequest, callBackFunction);
}
asyncRequest.open( 'GET', url, true ); // prepare the request
asyncRequest.send( null ); // send the request
} // end try
catch ( exception )
{
alert( 'Request failed.' );
} // end catch
} // end function getContent
// call function whith content when ready
function stateChange(asyncRequest, callBackFunction)
{
if ( asyncRequest.readyState == 4 && asyncRequest.status == 200 )
{
callBackFunction(asyncRequest.responseText);
} // end if
} // end function stateChange
奇妙な部分は、すべてのスタイルの動作に加えて、すべてのjavascript関数です。ただし、何らかの理由でページがフリーズしています...
非同期ロードのいくつかのソリューション:
//this function will work cross-browser for loading scripts asynchronously
function loadScript(src, callback)
{
var s,
r,
t;
r = false;
s = document.createElement('script');
s.type = 'text/javascript';
s.src = src;
s.onload = s.onreadystatechange = function() {
//console.log( this.readyState ); //uncomment this line to see which ready states are called.
if ( !r && (!this.readyState || this.readyState == 'complete') )
{
r = true;
callback();
}
};
t = document.getElementsByTagName('script')[0];
t.parentNode.insertBefore(s, t);
}
ページにすでにjQueryがある場合は、次を使用します。
$.getScript(url, successCallback)
*
さらに、ドキュメントのロードが完了する前にスクリプトがロード/実行されている可能性があります。つまり、イベントを要素にバインドする前にdocument.ready
を待つ必要があります。
コードを見ずに問題を具体的に伝えることはできません。
最も簡単な解決策は、ページの下部ですべてのスクリプトをインラインに保つことです。これにより、実行中にHTMLコンテンツの読み込みがブロックされません。また、必要な各スクリプトを非同期でロードする必要があるという問題も回避します。
常に使用されるわけではない、特別な派手なやり取りがあり、何らかの大きなスクリプトが必要な場合は、その特定のスクリプトが必要になるまでロードしないようにしてください(遅延ロード)。
* $.getScript
でロードされたスクリプトはキャッシュされない可能性が高い
Promise
オブジェクトなどの最新の機能を使用できる人は、loadScript
関数が大幅にシンプルになりました。
function loadScript(src) {
return new Promise(function (resolve, reject) {
var s;
s = document.createElement('script');
s.src = src;
s.onload = resolve;
s.onerror = reject;
document.head.appendChild(s);
});
}
返されたプロミスはコールバックを処理するため、このバージョンではcallback
引数を受け入れないことに注意してください。以前はloadScript(src, callback)
だったものが、今ではloadScript(src).then(callback)
になります。
これには、障害を検出して処理できるという追加のボーナスがあります。たとえば、次のような呼び出しができます.
loadScript(cdnSource)
.catch(loadScript.bind(null, localSource))
.then(successCallback, failureCallback);
... CDNの停止を適切に処理します。
HTML5の新しい「async」属性は、トリックを行うことになっています。 IEを気にする場合、ほとんどのブラウザで「遅延」もサポートされています。
async-HTML
<script async src="siteScript.js" onload="myInit()"></script>
defer-HTML
<script defer src="siteScript.js" onload="myInit()"></script>
新しいAdSenseの広告ユニットコードを分析しているときに、属性と検索に気付いたので、ここに進みます: http://davidwalsh.name/html5-async
ロードを完了したすべてのスクリプトがindex2.htmlが同じライブラリを使用するindex2.htmlにページをリダイレクトしたときに、スクリプトを非同期にロードしました(html 5にはその機能があります)。ページがindex2.htmlにリダイレクトされると、ブラウザにはキャッシュがあるため、ページをロードするために必要なものがすべて揃っているため、index2.htmlは1秒未満でロードされます。また、index.htmlページでは、使用する予定の画像を読み込み、ブラウザがそれらの画像をキャッシュに配置するようにします。だから私のindex.htmlは次のようになります:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Project Management</title>
<!-- the purpose of this page is to load all the scripts on the browsers cache so that pages can load fast from now on -->
<script type="text/javascript">
function stylesheet(url) {
var s = document.createElement('link');
s.type = 'text/css';
s.async = true;
s.src = url;
var x = document.getElementsByTagName('head')[0];
x.appendChild(s);
}
function script(url) {
var s = document.createElement('script');
s.type = 'text/javascript';
s.async = true;
s.src = url;
var x = document.getElementsByTagName('head')[0];
x.appendChild(s);
}
//load scritps to the catche of browser
(function () {
stylesheet('css/custom-theme/jquery-ui-1.8.16.custom.css');
stylesheet('css/main.css');
stylesheet('css/Marquee.css');
stylesheet('css/mainTable.css');
script('js/jquery-ui-1.8.16.custom.min.js');
script('js/jquery-1.6.2.min.js');
script('js/myFunctions.js');
script('js/farinspace/jquery.imgpreload.min.js');
script('js/Marquee.js');
})();
</script>
<script type="text/javascript">
// once the page is loaded go to index2.html
window.onload = function () {
document.location = "index2.html";
}
</script>
</head>
<body>
<div id="cover" style="position:fixed; left:0px; top:0px; width:100%; height:100%; background-color:Black; z-index:100;">Loading</div>
<img src="images/home/background.png" />
<img src="images/home/3.png"/>
<img src="images/home/6.jpg"/>
<img src="images/home/4.png"/>
<img src="images/home/5.png"/>
<img src="images/home/8.jpg"/>
<img src="images/home/9.jpg"/>
<img src="images/logo.png"/>
<img src="images/logo.png"/>
<img src="images/theme/contentBorder.png"/>
</body>
</html>
これに関するもう1つの良い点は、ページにローダーを配置し、ページの読み込みが完了するとローダーが消え、数ミリ秒で新しいページが実行されることです。
グーグルからの例
<script type="text/javascript">
(function() {
var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
po.src = 'https://apis.google.com/js/plusone.js?onload=onLoadCallback';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
})();
</script>
いくつかのメモ:
s.async = true
はHTML5 Doctypeに対してあまり正しくありません。正しいのはs.async = 'async'
です(実際にtrue
を使用するのは正しいです、 amn のおかげで) コメント のすぐ下)ファイルを非同期にロードする最近の理由があるので、順番に、私はあなたの例よりも機能的に駆動する方法をお勧めします(本番用のconsole.log
は削除してください:)):
(function() {
var prot = ("https:"===document.location.protocol?"https://":"http://");
var scripts = [
"path/to/first.js",
"path/to/second.js",
"path/to/third.js"
];
function completed() { console.log('completed'); } // FIXME: remove logs
function checkStateAndCall(path, callback) {
var _success = false;
return function() {
if (!_success && (!this.readyState || (this.readyState == 'complete'))) {
_success = true;
console.log(path, 'is ready'); // FIXME: remove logs
callback();
}
};
}
function asyncLoadScripts(files) {
function loadNext() { // chain element
if (!files.length) completed();
var path = files.shift();
var scriptElm = document.createElement('script');
scriptElm.type = 'text/javascript';
scriptElm.async = true;
scriptElm.src = prot+path;
scriptElm.onload = scriptElm.onreadystatechange = \
checkStateAndCall(path, loadNext); // load next file in chain when
// this one will be ready
var headElm = document.head || document.getElementsByTagName('head')[0];
headElm.appendChild(scriptElm);
}
loadNext(); // start a chain
}
asyncLoadScripts(scripts);
})();
HTML5のおかげで、タグに「async」を追加することで、非同期にロードするスクリプトを宣言できるようになりました。
<script async>...</script>
注:async属性は外部スクリプト専用です(src属性が存在する場合にのみ使用してください)。
注:外部スクリプトを実行する方法はいくつかあります。
これを参照してください: http://www.w3schools.com/tags/att_script_async.asp
async falseを使用してjsスクリプトのみを処理しますが、非同期スクリプトの読み込みに対する最新の優れたソリューションを次に示します。
www.html5rocks.comに書かれた素晴らしい記事があります- スクリプトの読み込みの濁った海に深く潜り込みます 。
考えられる多くの解決策を検討した後、著者は、jsスクリプトによるページレンダリングのブロックを回避するには、body要素の最後にjsスクリプトを追加することが最善の方法であると結論付けました。
その間に、著者は、スクリプトを非同期にロードして実行することを切望している人々のために、別の優れた代替ソリューションを追加しました。
script1.js, script2.js, script3.js, script4.js
という名前の4つのスクリプトがあることを考慮すると、applying async = falseで実行できます。
[
'script1.js',
'script2.js',
'script3.js',
'script4.js'
].forEach(function(src) {
var script = document.createElement('script');
script.src = src;
script.async = false;
document.head.appendChild(script);
});
さて、Spec says:一緒にダウンロードし、すべてダウンロードしたらすぐに順番に実行します。
Firefox <3.6、Operaのコメント:この「非同期」のことはわかりませんが、JSを介して追加されたスクリプトを追加順に実行します。
Safari 5.0のコメント:「非同期」は理解していますが、JSで「false」に設定することは理解できません。スクリプトが到着したらすぐに、どんな順序ででもスクリプトを実行します。
IE <10 says:「async」についてはわかりませんが、「onreadystatechange」を使用する回避策があります。
他のすべてのことを言う:私はあなたの友達です。これは本で行います。
今、IE <10回避策の完全なコード:
var scripts = [
'script1.js',
'script2.js',
'script3.js',
'script4.js'
];
var src;
var script;
var pendingScripts = [];
var firstScript = document.scripts[0];
// Watch scripts load in IE
function stateChange() {
// Execute as many scripts in order as we can
var pendingScript;
while (pendingScripts[0] && ( pendingScripts[0].readyState == 'loaded' || pendingScripts[0].readyState == 'complete' ) ) {
pendingScript = pendingScripts.shift();
// avoid future loading events from this script (eg, if src changes)
pendingScript.onreadystatechange = null;
// can't just appendChild, old IE bug if element isn't closed
firstScript.parentNode.insertBefore(pendingScript, firstScript);
}
}
// loop through our script urls
while (src = scripts.shift()) {
if ('async' in firstScript) { // modern browsers
script = document.createElement('script');
script.async = false;
script.src = src;
document.head.appendChild(script);
}
else if (firstScript.readyState) { // IE<10
// create a script and add it to our todo pile
script = document.createElement('script');
pendingScripts.Push(script);
// listen for state changes
script.onreadystatechange = stateChange;
// must set src AFTER adding onreadystatechange listener
// else we’ll miss the loaded event for cached scripts
script.src = src;
}
else { // fall back to defer
document.write('<script src="' + src + '" defer></'+'script>');
}
}
コールバックの存在をチェックしてzzzzBovの答えを完成させ、引数の受け渡しを許可します。
function loadScript(src, callback, args) {
var s, r, t;
r = false;
s = document.createElement('script');
s.type = 'text/javascript';
s.src = src;
if (typeof(callback) === 'function') {
s.onload = s.onreadystatechange = function() {
if (!r && (!this.readyState || this.readyState === 'complete')) {
r = true;
callback.apply(args);
}
};
};
t = document.getElementsByTagName('script')[0];
t.parent.insertBefore(s, t);
}
Modernizr をご覧になることをお勧めします。ファイルがロードされているかどうかを確認し、指定した他のスクリプトを実行できる機能を使用して、JavaScriptを非同期にロードできる小さな軽量ライブラリです。
Jqueryをロードする例を次に示します。
Modernizr.load([
{
load: '//ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.js',
complete: function () {
if ( !window.jQuery ) {
Modernizr.load('js/libs/jquery-1.6.1.min.js');
}
}
},
{
// This will wait for the fallback to load and
// execute if it needs to.
load: 'needs-jQuery.js'
}
]);
このWikiの記事は面白いかもしれません: http://ajaxpatterns.org/On-Demand_Javascript
このような手法をいつどのように使用するかについて説明します。
私はこれを助けるために小さな投稿を書きました、あなたはここでもっと読むことができます https://timber.io/snippets/asynchronously-load-a-script-in-the-browser-with-javascript/ =、しかし、私はヘルパークラスを以下に添付しました。スクリプトがロードされるのを自動的に待ち、指定されたウィンドウ属性を一度返します。
export default class ScriptLoader {
constructor (options) {
const { src, global, protocol = document.location.protocol } = options
this.src = src
this.global = global
this.protocol = protocol
this.isLoaded = false
}
loadScript () {
return new Promise((resolve, reject) => {
// Create script element and set attributes
const script = document.createElement('script')
script.type = 'text/javascript'
script.async = true
script.src = `${this.protocol}//${this.src}`
// Append the script to the DOM
const el = document.getElementsByTagName('script')[0]
el.parentNode.insertBefore(script, el)
// Resolve the promise once the script is loaded
script.addEventListener('load', () => {
this.isLoaded = true
resolve(script)
})
// Catch any errors while loading the script
script.addEventListener('error', () => {
reject(new Error(`${this.src} failed to load.`))
})
})
}
load () {
return new Promise(async (resolve, reject) => {
if (!this.isLoaded) {
try {
await this.loadScript()
resolve(window[this.global])
} catch (e) {
reject(e)
}
} else {
resolve(window[this.global])
}
})
}
}
使用方法は次のとおりです。
const loader = new Loader({
src: 'cdn.segment.com/analytics.js',
global: 'Segment',
})
// scriptToLoad will now be a reference to `window.Segment`
const scriptToLoad = await loader.load()
スクリプトの読み込みが非常に遅い理由の1つは、次のように、ページの読み込み中にすべてのスクリプトを実行していた場合です。
callMyFunctions();
の代わりに:
$(window).load(function() {
callMyFunctions();
});
この2番目のスクリプトは、ブラウザがすべてのJavascriptコードを完全にロードするまで待機してから、スクリプトの実行を開始し、ページがより速くロードされたように見せます。
ロード時間を短縮してユーザーエクスペリエンスを向上させたい場合は、「ロード画面」オプションを選択しません。私の意見では、単にページの読み込みを遅くするよりもずっと面倒です。
たとえば、誰かがReactで使用したい場合の小さなES6関数
import {uniqueId} from 'lodash' // optional
/**
* @param {String} file The path of the file you want to load.
* @param {Function} callback (optional) The function to call when the script loads.
* @param {String} id (optional) The unique id of the file you want to load.
*/
export const loadAsyncScript = (file, callback, id) => {
const d = document
if (!id) { id = uniqueId('async_script') } // optional
if (!d.getElementById(id)) {
const tag = 'script'
let newScript = d.createElement(tag)
let firstScript = d.getElementsByTagName(tag)[0]
newScript.id = id
newScript.async = true
newScript.src = file
if (callback) {
// IE support
newScript.onreadystatechange = () => {
if (newScript.readyState === 'loaded' || newScript.readyState === 'complete') {
newScript.onreadystatechange = null
callback(file)
}
}
// Other (non-IE) browsers support
newScript.onload = () => {
callback(file)
}
}
firstScript.parentNode.insertBefore(newScript, firstScript)
} else {
console.error(`The script with id ${id} is already loaded`)
}
}
レンダリングをブロックするJavaScriptを排除するためのカスタムソリューションを次に示します。
// put all your JS files here, in correct order
const libs = {
"jquery": "https://code.jquery.com/jquery-2.1.4.min.js",
"bxSlider": "https://cdnjs.cloudflare.com/ajax/libs/bxslider/4.2.5/jquery.bxslider.min.js",
"angular": "https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0-beta.2/angular.min.js",
"ngAnimate": "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0-beta.2/angular-animate.min.js"
}
const loadedLibs = {}
let counter = 0
const loadAsync = function(lib) {
var http = new XMLHttpRequest()
http.open("GET", libs[lib], true)
http.onload = () => {
loadedLibs[lib] = http.responseText
if (++counter == Object.keys(libs).length) startScripts()
}
http.send()
}
const startScripts = function() {
for (var lib in libs) eval(loadedLibs[lib])
console.log("allLoaded")
}
for (var lib in libs) loadAsync(lib)
要するに、すべてのスクリプトを非同期にロードし、結果としてそれらを実行します。
Githubリポジトリ: https://github.com/mudroljub/js-async-loader
これを確認してください https://github.com/stephen-lazarionok/async-resource-loader 。 JS、CSS、および複数のファイルをワンショットでロードする方法を示す例があります。
まあ、x.parentNode
はHEAD要素を返すので、headタグの直前にスクリプトを挿入しています。たぶんそれが問題です。
代わりにx.parentNode.appendChild()
を試してください。
Fetch Injectionの使用を検討しましたか? fetch-inject と呼ばれるオープンソースライブラリを展開して、このようなケースを処理しました。 libを使用すると、ローダーは次のようになります。
fetcInject([
'js/jquery-1.6.2.min.js',
'js/Marquee.js',
'css/Marquee.css',
'css/custom-theme/jquery-ui-1.8.16.custom.css',
'css/main.css'
]).then(() => {
'js/jquery-ui-1.8.16.custom.min.js',
'js/farinspace/jquery.imgpreload.min.js'
})
後方互換性のために、機能検出とXHRインジェクションまたはスクリプトDOM要素へのフォールバックを活用するか、document.write
を使用してタグをページに単純にインライン化します。