在JavaScript應(yīng)用中實現(xiàn)延遲加載的方法
無論簡單還是復(fù)雜的Web應(yīng)用,都由一些HTML、JavaScript、CSS文件組成。通常開發(fā)者會通過JQuery、Knockout、Underscore等等這樣的第三方JavaScript框架來提高開發(fā)速度。由于這些JavaScript框架都針對特定的用途開發(fā)而且已經(jīng)得到了“驗證”,所以直接使用它們就比自己從頭實現(xiàn)所需要的功能顯得更為合適。然而,伴隨著應(yīng)用的復(fù)雜度不斷上升,寫出干凈、低耦合、可維護的代碼變得越來越重要。在這篇文章里,我將解釋RequireJS框架如何幫助應(yīng)用開發(fā)者寫出更加模塊化的代碼,以及它是如何通過延遲加載JavaScript文件來提高應(yīng)用性能的。
開始的部分我們先不用RequireJS框架,然后在下一個章節(jié)用RequireJS來重構(gòu)它。
下面的這個HTML頁面包含了一個id為“message”的<p>元素。當(dāng)用戶訪問這個頁面的時候,它將展示訂單Id和客戶姓名信息。
Common.JS文件包含了兩個模塊的定義——Order和Customer。函數(shù)showData和頁面的body結(jié)合在一起,它通過調(diào)用write函數(shù)來把要輸出的信息放入頁面中。作為示例,我在showData函數(shù)里硬編碼了Id為1,客戶姓名為Prasad。
<!DOCTYPE html> <html> <head> <title>JavaScript NonRequireJS</title> <script src="common.js" type="text/javascript"></script> </head> <body> <strong>Display data without RequireJS</strong> <p id="message" /> <script type="text/javascript"> showData(); </script> </body> </html> Common.JS
function write(message) { document.getElementById('message').innerHTML += message + '</br>'; } function showData() { var o = new Order(1, "Prasad"); write("Order Id : " + o.id + " Customer Name : " + o.customer.name); } function Customer(name) { this.name = name; return this; } function Order(id, customerName) { this.id = id; this.customer = new Customer(customerName); return this; }
在瀏覽器中打開這個頁面,你將看到如下的信息。
雖然上面的代碼能夠顯示輸出,但是它仍有一些問題:
- Common.JS文件包含了所有需要定義的函數(shù)(write,showData),而且模塊(Order,Customer)很難維護和復(fù)用。假如你想在其它頁面里復(fù)用write函數(shù)并引用了上面的JavaScript文件,那么你也導(dǎo)入了這個頁面可能不需要的其它函數(shù)和模塊。
- Order模塊(或者在面向?qū)ο笾薪凶觥邦悺保┰诔跏蓟^程中創(chuàng)建了一個Customer模塊的實例。這意味著Order模塊依賴于Customer模塊。這些模塊間的緊耦合使得將來在優(yōu)化時很難重構(gòu)與維護。
- 每當(dāng)客戶端請求這個頁面時,Common.JS文件就會被載入DOM。在上面這個例子中,盡管我們只需要在頁面上輸出信息,但我們?nèi)园涯切┎恍枰哪K(Customer,Order)載入了內(nèi)存。載入不必要的應(yīng)用資源(JavaScript、CSS、圖片文件等等)會降低應(yīng)用的性能。
- Common.JS文件里的模塊可以被分離到不同的JavaScript文件里,但是當(dāng)應(yīng)用變得越來越復(fù)雜時,很難判斷JavaScript文件之間的依賴關(guān)系與需要被加載的文件的加載順序。
RequireJS框架處理了JavaScript文件間的依賴關(guān)系,并且根據(jù)需要按順序加載它們。
用RequireJS搭建應(yīng)用
現(xiàn)在讓我們看看重構(gòu)過的代碼。下面的HTML代碼引用了Require.JS文件。data-main屬性定義了這個頁面的唯一入口點。在下面這個場景中,它告訴了RequireJS在啟動的時候加載Main.js。
<!DOCTYPE html> <html> <head> <title>JavaScript RequireJS</title> <script src="Require.Js" type="text/javascript" data-main="Main.js"></script> </head> <body> <strong>Display data using RequireJS</strong> <p id="message" /> </body> </html>
Main.JS
由于這個文件已經(jīng)通過data-main屬性指定,RequireJS將會盡快的加載它。這個文件使用了RequireJS框架的函數(shù)來確定和定義對于其它JavaScript文件的依賴關(guān)系。在下面的代碼片段里,第一個參數(shù)表示依賴關(guān)系(依賴Order.JS文件),第二個參數(shù)為一個回調(diào)函數(shù)。RequireJS分析所有的依賴關(guān)系并載入它們,然后執(zhí)行這個回調(diào)函數(shù)。請注意,第一個參數(shù)的值(Order)必須和文件名一致(Order.JS)。
require(["Order"], function (Order) { var o = new Order(1, "Prasad"); write(o.id + o.customer.name); });
Order.JS
RequireJS框架提供了一個定義和維護JavaScript文件間依賴關(guān)系的簡便途徑。下面代碼中的define函數(shù)聲明了Customer.JS必須在處理Order回調(diào)函數(shù)前載入。
define(["Customer"], function (Customer) { function Order(id, custName) { this.id = id; this.customer = new Customer(custName); } return Order; } );
Customer.JS
這個文件不依賴于任何其它JavaScript文件,所以define函數(shù)的第一個參數(shù)的值是一個空數(shù)組。
define([], function () { function Customer(name) { this.name = name; } return Customer; } );
好了,現(xiàn)在用你的瀏覽器打開這個應(yīng)用,你將會看到如下的輸出。要注意的是RequireJS只載入了必需的JavaScript文件。
總結(jié)
在這篇文章里,我們分析了RequireJS框架是如何處理JavaScript文件間的依賴關(guān)系并根據(jù)需要載入它們的。它能夠幫助開發(fā)者寫出更松耦合、更模塊化且更具有可維護性的代碼。
謝謝
下載源代碼: Lazy Loading using RequireJS (Prasad Honrao, Codetails)
相關(guān)文章
定義JavaScript二維數(shù)組采用定義數(shù)組的數(shù)組來實現(xiàn)
javaScript沒有提供直接定義二維數(shù)組的方法,但可以使用定義數(shù)組的數(shù)組來定義JavaScript二維數(shù)組,需要的朋友可以了解下2012-12-12javascript標(biāo)準(zhǔn)庫(js的標(biāo)準(zhǔn)內(nèi)置對象)總結(jié)
這篇文章主要介紹了javascript標(biāo)準(zhǔn)庫,標(biāo)準(zhǔn)庫指的是js的標(biāo)準(zhǔn)內(nèi)置對象,是js這門語言本身初始時提供的在全局范圍的對象,需要的朋友可以參考下2018-05-05JavaScript那些不經(jīng)意間發(fā)生的數(shù)據(jù)類型自動轉(zhuǎn)換
JavaScript可以自由的進行數(shù)據(jù)類型轉(zhuǎn)換,但是更多的情況下,是由JavaScript自動轉(zhuǎn)換的。本文就將為大家詳細講解那些不經(jīng)意間發(fā)生的數(shù)據(jù)類型轉(zhuǎn)換,感興趣的同學(xué)可以了解一下2022-02-02javascript學(xué)習(xí)筆記(十三) js閉包介紹(轉(zhuǎn))
閉包(closure)是Javascript語言的一個難點,也是它的特色,很多高級應(yīng)用都要依靠閉包實現(xiàn)2012-06-06