優化網站設計(十七):延遲或按需加載內容


前言

網站設計的優化是一個很大的話題,有一些通用的原則,也有針對不同開發平台的一些建議。這方面的研究一直沒有停止過,我在不同的場合也分享過這樣的話題。

作為通用的原則,雅虎的工程師團隊曾經給出過35個最佳實踐。這個列表請參考  Best Practices for Speeding Up Your Web Site http://developer.yahoo.com/performance/rules.html,同時,他們還發布了一個相應的測試工具Yslow http://developer.yahoo.com/yslow/

我強烈推薦所有的網站開發人員都應該學習這些最佳實踐,並結合自己的實際項目情況進行應用。 接下來的一段時間,我將結合ASP.NET這個開發平台,針對這些原則,通過一個系列文章的形式,做些講解和演繹,以幫助大家更好地理解這些原則,並且更好地使用他們。

准備工作

為了跟隨我進行后續的學習,你需要准備如下的開發環境和工具

  1. Google Chrome 或者firefox ,並且安裝 Yslow這個擴展組件.請注意,這個組件是雅虎提供的,但目前沒有針對IE的版本。
    1. https://chrome.google.com/webstore/detail/yslow/ninejjcohidippngpapiilnmkgllmakh
    2. https://addons.mozilla.org/en-US/firefox/addon/yslow/
    3. 你應該對這些瀏覽器的開發人員工具有所了解,你可以通過按下F12鍵調出這個工具。
  2. Visaul Studio 2010 SP1 或更高版本,推薦使用Visual Studio 2012
    1. http://www.microsoft.com/visualstudio/eng/downloads
  3. 你需要對ASP.NET的開發基本流程和核心技術有相當的了解,本系列文章很難對基礎知識做普及。

本文要討論的話題

這一篇我和大家討論的是第十六條原則:Postload Components延遲按需加載內容)

頁面加載過程中,除了頁面本身的內容之外,可能需要加載很多額外的資源,例如我們常說的:

  1. 腳本
  2. 樣式表
  3. 圖片

我在之前的文章中,已經有針對腳本和樣式表做了一些優化的建議,請參考

  1. 優化網站設計(二):使用CDN

  2. 優化網站設計(五):在頂部放置樣式定義

  3. 優化網站設計(六):在文檔底部放置腳本定義或引用

  4. 優化網站設計(八):將腳本文件和樣式表作為外部文件引用

  5. 優化網站設計(十):最小化JAVASCRIPT和CSS

  6. 優化網站設計(十二):刪除重復腳本

這一條原則的核心是:延遲或按需加載。首先來針對我們比較最經常用到的腳本為例進行講解。

針對腳本的按需加載

我們可以想象一下,一個真正的網站項目中,會有各種各樣的腳本文件,其中還包含很多基礎的框架(例如jquery,knockoutjs 等),這些腳本文件可能都或多或少需要在頁面中引用。問題在於,如果頁面一多起來,或者復雜起來,我們可能不太能准確地知道某個頁面是否真的需要某個腳本。(難道不是這樣嗎?),一個蹩腳的解決方案是,那么就在母版頁中,一次性將所有可能用到的框架腳本都引用進來吧。你是這樣做的嗎?

如果你真的這樣做,那么,可能可以一時地解決問題。但實際上存在一個問題,在某些頁面上,可能只用到一個腳本庫,但為了你的方便,以后都需要全部加載所有的腳本庫了。

隨着項目的進一步開發,腳本之間的依賴會進一步復雜,要維護這些腳本確實是一個大問題。

在當年雅虎的團隊寫下這條原則的時候,他們提到了一個他們自己開發的組件來實現按需加載腳本,這個組件叫做GET,是包含在YUI這套工具包中的。http://yuilibrary.com/yui/docs/get/  ,它的意思就是可以動態地,按需加載腳本和樣式表。

我對YUI的研究並不太多,而實際上這幾年,Javascript這方面的技術突飛猛進,涌現了更多的創新性的設計。例如我今天要講的requirejs

我通過一個簡單的例子給大家來講解吧

image

這里有一個簡單的網站,首頁叫Default.aspx。根據我們的設計,這個頁面需要加載jquery,以及可能的其他一些庫,然后執行自己的一些邏輯。所以,我們會有如下的腳本引用

    <!--傳統的做法中,我們需要在頁面中添加所有的腳本引用,有時候可能會加載一些不必要的腳本-->
    <script src="Scripts/jquery-2.0.0.min.js"></script>
    <script src="Scripts/knockout-2.2.1.js"></script>
    <script src="Scripts/default.js"></script>

這樣做有什么問題嗎?當然不是。只不過如我們之前所談到的那樣,這種預先加載所有腳本的方式,可能造成資源的浪費,而且這么多腳本引用在頁面中,很容易引起混淆。為了更好地說明這一點,我給大家演示一個真實的場景:

  1. 我們希望頁面在加載的時候,只下載jquery這個庫
  2. 只有當用戶點擊了頁面上面的那個按鈕,我們才去下載knockout這個庫

瞧!這就是所謂的按需加載。那么來看看我們將如何使用requirejs實現這個需求吧?

首先,你可以通過Nuget Package Manager 獲取requirejs這個庫。

image

然后,在頁面中,你只需要像下面這樣定義腳本引用。(以后,你的頁面中也只需要有這樣一個引用)

    <script src="Scripts/require.js" data-main="scripts/default"></script>

這里的data-main指的是主腳本。require.js會首先下載的一個腳本。你確實可以寫成下面這樣

    <script src="Scripts/require.js" data-main="scripts/default.js"></script>

但是,正如你所見,.js是可以省略掉的。

接下來在default.js中,應該如何寫腳本呢?下面是一個簡單的例子

/// <reference path="require.js" />
/// <reference path="jquery-2.0.0.js" />
/// <reference path="knockout-2.2.1.js" />


//對requirejs進行一些基本配置
requirejs.config({
    paths: {
        jquery: "jquery-2.0.0.min" //指定一個路徑別名
        , knockout: "knockout-2.2.1"
    }
});


//聲明下面的代碼是需要jquery這個庫的
require(['jquery'], function () {
    $(function () {
        alert("Hello,jquery!");
    });
});

 

我們看到,第一部分是對requirejs的基本配置,我們定義了兩個別名。然后在第二部分,我們聲明了下面的代碼是需要jquery這個庫的。

將頁面運行起來之后,在瀏覽器中我們可以監控得到腳本下載的行為如下

image

如我們設想的那樣,先加載了require.js,然后加載了default.js, 然后才是加載了jquery.js

有點意思,不是嗎?雖然最后的結果也是加載了jquery,但這個加載方式與直接在頁面中定義引用有着本質的區別,這是按需加載的。如果你對此還不太贊同,那么看了下面的例子,我相信你一定會同意的。

我們需要在default.js這個文件中,為頁面上的那個按鈕訂閱點擊事件,而且我們希望,只有當用戶真的點擊過了按鈕,才會下載另外一個腳本(knockout),看看如何實現這個需求吧?

/// <reference path="require.js" />
/// <reference path="jquery-2.0.0.js" />
/// <reference path="knockout-2.2.1.js" />


//對requirejs進行一些基本配置
requirejs.config({
    paths: {
        jquery: "jquery-2.0.0.min" //指定一個路徑別名
        , knockout: "knockout-2.2.1"
    }
});



//聲明下面的代碼是需要jquery這個庫的
require(['jquery'], function ($) {
    $(function () {
        //只有用戶點擊了某個按鈕,才動態加載knockoutjs
        $("#test").click(
            function () {
                require(['knockout'], function (ko) {
                    alert(ko.version);
                });
            }
        );
    });
});
 
同樣的,我們可以通過瀏覽器監控工具了解腳本下載的流程:
頁面加載的時候,仍然只有三個腳本下載了
image
但是,如果點擊了按鈕,則會有第四個腳本下載
image
同時,從下面的對話框來看,也可以斷定確實是執行了相應的腳本的。因為我們當前使用的knockout腳本的版本確實是2.2.1。
image
 
這的確是一個很不錯的機制。如果大家有興趣,還可以繼續深入研究,現在jquery為了更好地滿足動態加載和按需加載的需要,甚至都提供了模塊化的版本。請參考 http://projects.jga.me/jquery-builder/

 

針對樣式表文件的按需加載

我相信按需加載腳本文件這樣的設計,足夠引起你的興趣了。很自然地,你可能會有這樣一個問題,能不能實現對樣式表的按需加載呢?

聽起來不錯,而且應該也不難,但目前沒有現成的實現。當然YUI中的GET是可以用的。

requirejs的官方有一個解釋,有興趣可以參考一下  http://requirejs.org/docs/faq-advanced.html#css

他們也提供了一個建議的腳本來按需加載樣式表

function loadCss(url) {
    var link = document.createElement("link");
    link.type = "text/css";
    link.rel = "stylesheet";
    link.href = url;
    document.getElementsByTagName("head")[0].appendChild(link);
}

你可以將這個腳本訪問任何的地方,進行調用。例如我是下面這樣做的

/// <reference path="require.js" />
/// <reference path="jquery-2.0.0.js" />
/// <reference path="knockout-2.2.1.js" />


//對requirejs進行一些基本配置
requirejs.config({
    paths: {
        jquery: "jquery-2.0.0.min" //指定一個路徑別名
        , knockout: "knockout-2.2.1"
    }
});



//聲明下面的代碼是需要jquery這個庫的
require(['jquery'], function ($) {
    $(function () {
        //只有用戶點擊了某個按鈕,才動態加載knockoutjs
        $("#test").click(
            function () {
       loadCss('default.css');

                require(['knockout'], function (ko) {
                    alert(ko.version);
                });
            }
        );
    });
});



function loadCss(url) {
    var link = document.createElement("link");
    link.type = "text/css";
    link.rel = "stylesheet";
    link.href = url;
    document.getElementsByTagName("head")[0].appendChild(link);
}

 

針對圖片的按需加載

本文的最后一部分我們來談談圖片的按需加載的問題。如果你的頁面包含了大量的圖片,掌握這個原則將非常有助於提高網頁的加載速度。

大家可以設想一下圖片搜索引擎的結果頁面,例如 https://www.google.com/search?newwindow=1&site=&tbm=isch&source=hp&biw=1468&bih=773&q=microsoft&oq=microsoft&gs_l=img.3...1779.4076.0.4399.9.7.0.0.0.0.0.0..0.0...0.0...1ac.1j4.12.img.aajYF7y8xW8

我在images.google.com中搜索microsoft,毫無疑問,這會返回成千上萬張圖片。

imageimage

那么,這些圖片是不是要一次性全部加載進來呢?顯然不可能,你可能會說,應該做分頁會不會好一些?分頁通常是一個好技術,但在搜索引擎的頁面中,分頁不是一個很好的選擇(作為用戶並不見得願意去點擊頁面導航按鈕),目前主流的是圖片搜索引擎的做法都是不采用分頁,而是隨着用戶的滾動條滑動來按需獲取圖片。

這是一個相當重要的設計,但稍微思考一下,應該不是很簡單的一個工作。幸運的是,雅虎的團隊提供了一個很好的組件(ImageLoader)可以直接使用:http://yuilibrary.com/yui/docs/imageloader/ 

關於這個組件的用法,有幾個在線的演示頁面:

如果你習慣用jquery,那么可以參考一下下面這個說明

http://www.appelsiini.net/projects/lazyload

 

     


免責聲明!

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



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