14

問題

ページのパフォーマンスを向上させるには、下部のページで実行する必要のあるスクリプトをプリロードする必要があります。

スクリプトがいつ解析、コンパイル、実行されるかを制御したいと思います。

スクリプトタグは一般的なレンダリングエンジン(geekoなど)のブロッカーであるため、避ける必要があります。

スクリプトの実行時期を制御する必要があるため、 deferプロパティを使用してロードできません。また、非同期プロパティは可能ではありません。

サンプル:

<html><head>
//preload scripts ie: a.js  without use the script
</head><body> ..... all my nice html here
//execute here a.js
</body></html>

これにより、ブラウザがスクリプトコンテンツのダウンロードを開始し、同時にページを並行してレンダリングするため、ページのレンダリングパフォーマンスを最大化できます。最後に、スクリプトタグを追加して、ブラウザがコードを解析、コンパイル、実行できるようにします。

私がそれを行うことができる唯一の方法は、隠し画像タグを使用することです。(これはStoyanの簡略版です)

すなわち

 <html><head>
 <img src="a.js" style=display:none;>
</head><body> ..... all my nice html here
 <script src="a.js">  
</body></html>

質問

このテクニックを使用しても問題は見つかりませんでしたが、これを行うためのより良い方法を知っている人はいますか?メタプリフェッチはありますか?

追加情報

私はrequirejsを使用しているので、モジュールコードを実行せずにプリロードしようとしています。これは、このコードがDOM要素に依存しているためです。

4

6 に答える 6

6

同様の手法imgで、Internet Explorerに使用してスクリプトとスタイルシートをプリロードobjectし、他のすべてのブラウザにタグを付けることができます。

var isMSIE = /*@cc_on!@*/false;

var resources = ['a.js', 'b.js', 'c.css'];

for (var i=0; i<resources.length; i++){
  if (isMSIE){
    new Image().src = resources[i];
  } else {
    var o = document.createElement('object');
    o.data = resources[i];
    document.body.appendChild(o);
  }
}

このような手法を説明し、警告の概要を説明するブログ投稿があります。実行せずにCSS/JavaScriptをプリロードします。

しかし、他の回答で提案されているように、動的に追加されたスクリプトを使用したくないのはなぜですか。これにより、より制御性の高い、よりクリーンなソリューションが実現する可能性があります。

于 2012-06-19T14:25:26.873 に答える
5

prefetchリンクタグの属性を使用して、JavaScriptを含む任意のリソースをプリロードできます。この記事の執筆時点(2016年8月10日)では、Safariではサポートされていませんが、他のほとんどの場所でサポートされています。

<link rel="prefetch" href="(url)">

ここでのサポートの詳細:http: //caniuse.com/#search=prefetch

IE 9,10は、caniuseMicrosoftがサポートを終了したため、マトリックスにリストされていないことに注意してください。

ここ詳細があり、プリレンダーなどのプリロードのオプションがあります

于 2016-08-10T13:25:40.300 に答える
1

実行せずにダウンロードするスクリプトごとに、名前とURLを含むオブジェクトを作成し、それらのオブジェクトを配列に配置します。

配列をループし、withを使用jQuery.ajaxdataType: "text"てスクリプトをテキストとしてダウンロードします。ajax呼び出しのdoneハンドラーで、ファイルのテキストコンテンツ(最初の引数で渡される)を適切なオブジェクトに格納し、カウンターをインクリメントし、そのカウンターがファイルの数と等しい場合に「alldone」関数を呼び出します。この方法でダウンロードしています。

「alldone」関数(またはそれ以降)で、次の手順を実行します。配列を再度ループし、エントリごとに、、を使用して、document.createElement("script")「src」属性ではなく、目的のソースをインラインで持つスクリプトを動的に生成します。最後に、doを実行します。これは、そのスクリプトが実行されるポイントです。document.createTextNode(...)(...scriptNode...).appendChild(...)document.head.appendChild(...scriptNode...)

私は、フレームを使用する必要があるプロジェクトでこの手法を使用しました。これらのファイルのそれぞれがサーバーから1回だけ要求されるようにするために、複数のフレームやフレームセットに同一のJavaScriptファイルが必要です。

コード(テスト済みで動作中)は次のとおりです

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
<html>
    <head>
        <script id="scriptData">
            var scriptData = [
                { name: "foo"    , url: "path/to/foo"    },
                { name: "bar"    , url: "path/to/bar"    }
            ];
        </script>
        <script id="scriptLoader">
            var LOADER = {
                loadedCount: 0,
                toBeLoadedCount: 0,
                load_jQuery: function (){
                    var jqNode = document.createElement("script");
                    jqNode.setAttribute("src", "/path/to/jquery");
                    jqNode.setAttribute("onload", "LOADER.loadScripts();");
                    jqNode.setAttribute("id", "jquery");
                    document.head.appendChild(jqNode);
                },
                loadScripts: function (){
                    var scriptDataLookup = this.scriptDataLookup = {};
                    var scriptNodes = this.scriptNodes = {};
                    var scriptNodesArr = this.scriptNodesArr = [];
                    for (var j=0; j<scriptData.length; j++){
                        var theEntry = scriptData[j];
                        scriptDataLookup[theEntry.name] = theEntry;
                    }
                    //console.log(JSON.stringify(scriptDataLookup, null, 4));
                    for (var i=0; i<scriptData.length; i++){
                        var entry = scriptData[i];
                        var name = entry.name;
                        var theURL = entry.url;
                        this.toBeLoadedCount++;
                        var node = document.createElement("script");
                        node.setAttribute("id", name);
                        scriptNodes[name] = node;
                        scriptNodesArr.push(node);
                        jQuery.ajax({
                            method   : "GET",
                            url      : theURL,
                            dataType : "text"
                        }).done(this.makeHandler(name, node)).fail(this.makeFailHandler(name, node));
                    }
                },
                makeFailHandler: function(name, node){
                    var THIS = this;
                    return function(xhr, errorName, errorMessage){
                        console.log(name, "FAIL");
                        console.log(xhr);
                        console.log(errorName);
                        console.log(errorMessage);
                        debugger;
                    }
                },
                makeHandler: function(name, node){
                    var THIS = this;
                    return function (fileContents, status, xhr){
                        THIS.loadedCount++;
                        //console.log("loaded", name, "content length", fileContents.length, "status", status);
                        //console.log("loaded:", THIS.loadedCount, "/", THIS.toBeLoadedCount);
                        THIS.scriptDataLookup[name].fileContents = fileContents;
                        if (THIS.loadedCount >= THIS.toBeLoadedCount){
                            THIS.allScriptsLoaded();
                        }
                    }
                },
                allScriptsLoaded: function(){
                    for (var i=0; i<this.scriptNodesArr.length; i++){
                        var scriptNode = this.scriptNodesArr[i];
                        var name = scriptNode.id;
                        var data = this.scriptDataLookup[name];
                        var fileContents = data.fileContents;
                        var textNode = document.createTextNode(fileContents);
                        scriptNode.appendChild(textNode);
                        document.head.appendChild(scriptNode); // execution is here
                        //console.log(scriptNode);
                    }
                    // call code to make the frames here
                }
            };
        </script>
    </head>
    <frameset rows="200pixels,*" onload="LOADER.load_jQuery();">
        <frame src="about:blank"></frame>
        <frame src="about:blank"></frame>
    </frameset>
</html>

上記のアプローチに密接に関連する 他の質問他の関連する質問

于 2017-02-27T13:32:36.220 に答える
0

これを試してみませんか?

var script = document.createElement('script');
script.src = 'http://path/to/your/script.js';
script.onload = function() {
  // do something here
}

document.head.appendChild(script);

.onloadイベントを使用して、いつロードされるかを制御できます。注意点の1つは、.onload()がIEで機能しないため、次のように使用できることです。

script.onreadystatechange = function() {
  if (/^loaded|complete$/i.test(this.readyState)) {
    // loaded
  };
}

さらに、DOMを介してスクリプトを追加することは非ブロッキングであり、このアプローチで目標を完全に達成できると思います。

于 2012-06-19T14:08:27.867 に答える
0

次のリンクをご覧ください。

http://calendar.perfplanet.com/2011/lazy-evaluation-of-commonjs-modules/

http://tomdale.net/2012/01/amd-is-not-the-answer/

そして、ember.jsがminispadeと呼ばれるツールを使用し、rubyで前処理して、javascriptモジュールのロード、解析、実行のプロセスを高速化しています。

于 2012-06-19T20:30:28.690 に答える
0

私はそこで同じ質問に答えました:

https://stackoverflow.com/a/46121439/1951947

タグを使用してスクリプトをプリロードするだけで、タグ<link>と一緒に使用できます<script>

例えば:<link href="/js/script-to-preload.js" rel="preload" as="script">

于 2017-09-08T17:09:23.820 に答える