requirejs:性能優化-及早並行加載


為了提高頁面的性能,通常情況下,我們希望資源盡可能地早地並行加載。這里有兩個要點,首先是盡早,其次是並行。

通過data-main方式加載要盡可能地避免,因為它讓requirejs、業務代碼不必要地串行起來。下面就講下如何盡可能地利用瀏覽器並行加載的能力來提高性能。

低效串行:想愛但卻無力

最簡單的優化,下面的例子中,通過兩個並排的script標簽加載require.js、main.js,這就達到了require.js、main.js並行加載的目的。

但這會有個問題,假設main.js依賴了jquery.js、anonymous.js(如下代碼所示),那么,只有等main.js加載完成,其依賴模塊才會開始加載。這顯然不夠理想,后面我們會講到如何避免這種情況,下面是簡單的源碼以及效果示意圖。

demo.html

<!DOCTYPE html>
<html>
<head></head>
<body>
<h1>main.js、anynomous.js串行加載</h1>

<script type="text/javascript" src="js/require.js"></script>
<script type="text/javascript" src="js/main.js"></script>

</body>
</html>

js/main.js:

require(['js/anonymous'], function(Anonymous) {
    alert('加載成功');
});

js/anonymous.js:

define(['js/jquery'], function() {
    console.log('匿名模塊,require直接報錯了。。。');
    return{
        say: function(msg){
            console.log(msg);
        }
    }
});

最終效果: Alt text

簡單匿名:一條走不通的路

正常情況下,假設頁面里有如下幾個<script>標簽,現代瀏覽器就會並發請求文件,並順序執行。但在requirejs里,如果這樣做的話,可能會遇到一些意料之外的情況。如下所示,四個並排的標簽,依次請求了require.jsjquery.jsanonymous.jsmain.js

demo.html:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>demo</title>
</head>
<body>
<h1>requirejs並行加載例子</h1>

<script type="text/javascript" src="js/require.js"></script>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/anonymous.js"></script>
<script type="text/javascript" src="js/main.js"></script>

</body>
</html>

預期中,資源會並行加載,但實際上,你會在控制台里看到下面的錯誤日志。

Alt text

為什么呢?對於requirejs來說,上面的js/anonymous.js是一個匿名的模塊,requirejs對它一無所知。當你在main中告訴requirejs說我要用到js/anonymous這個模塊時,它就傻眼了。所以,這里就直接給你報個錯誤提個醒:不要這樣寫,我不買賬。

那么,及早並行加載的路是否走不通了呢?未必,請繼續往下看。

答案就在身邊:注冊為命名模塊的jquery

簡單改下上面的例子,比如這樣,然后。。它就行了。。

<script type="text/javascript" src="js/require.js"></script>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/main.js"></script>

Alt text

原因很簡單。因為jquery把自己注冊成了命名模塊。requirejs於是就認得jquery了。

if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
    define( "jquery", [], function () { return jQuery; } );
}

jquery的啟發:起個好名字很重要

上面我們看到,給模塊起個名字,將匿名模塊改成命名模塊(named module),就開啟了我們的並行加載之旅。從這點看來,起名字真的很重要。

那么我們對之前的例子進行簡單的改造。這里用了個小技巧,利用命名模塊js/name-module.js來加載之前的匿名模塊js/anonymous.js。可以看到,requirejs不報錯了,requirejs跟name-module.js也並行加載了。

demo.html:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">

<title>demo</title>
</head>
<body>
<h1>並行加載requirejs、jquery</h1>

<script type="text/javascript" src="js/require.js"></script>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/name-module.js"></script>
<script type="text/javascript" src="js/main.js"></script>

</body>
</html>

js/name-module.js

define('name-module', 'js/anonymous', [], function() {
    return {
        say: function(msg){
            alert(msg);
        }
    };
});

最終效果圖: 

Alt text

通往希望之門:解決anonymous模塊的串行問題

如果你能耐着性子看到這一節,說明少年你已經發現了上一節很明顯的一個問題:盡管name-module.js並行加載了,但anonymou.js其實還是串行加載,那做這個優化還有什么意義? 

Alt text

沒錯,如果最終優化效果這樣的話,那是完全無法接受的。不賣關子,這個時候就要請出我們的requirejs打包神器r.js。通過打包優化,將anonymous.jsname-module.js打包生成一個文件,就解決了串行的問題。

1、安裝打包工具

npm install -g requirejs

2、創建打包配置文件,注意,由於jquery.js比較通用,一般情況下會單獨加載,所以從打包的列表里排除

{
    "appDir": "./",  // 應用根路徑
    "baseUrl": "./",  // 
    "dir": "dist",  // 打包的文件生成到哪個目錄
    "optimize": "none", // 是否壓縮
    "modules": [
        {
            "name": "js/name-module",
            "exclude": [
                "jquery"  // 將jqury從打包規則里排除
            ]
        }
    ]
}

3、運行如下命令打包

r.js -o ./build.js

4、打包后的name-module,可以看到,匿名模塊也被打包進去,同時被轉換成了命名模塊

define('js/anonymous',['jquery'], function() {
    console.log('匿名模塊,require直接報錯了。。。');
    return{
        say: function(msg){
            console.log('anonymous: '+msg);
        }
    }
});
define('js/name-module', ['js/anonymous'], function() {
    return {
        say: function(msg){
            alert('name module: '+msg);
        }
    };
});

5、再次訪問demo.html,很好,就是我們想要的結果 

Alt text

寫在后面

上面主要提供了及早並行加載的思路,但在實際利用requirejs打包的過程中,還會遇到一些需要小心處理的細節問題,當然也有一些坑。后面有時間再總結一下。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM