javascript動態加載


這兩天,沒什么太多的事情,好吧,我承認,是我這兩天不想做公司的項目,因為我突發奇想,其實也不算突發奇想,算是對以前的想法的實現,就是把JS當做Java來寫。
現在也有很多JS動態加載的框架,比如In.js。但是這種並不是我想要的編寫方式,我來說說我的想法。
先來一段java代碼
import Biz.User; User u = new User(); u.show();

按流程就是導包、實例化、調用。

JS是做不了導包的,或者說代碼意義上的導包,一般只是在頁面上進行script標簽的引入。
那么 先假設需要寫成這樣
Using("User"); var u = new User(); u.show();

那么,在JS里面可以實現嗎?

來一句一句的分析,當然,前提是頁面並不用script標簽載入user.js,不然就沒意義了。
第一句
Using("User");

為什么用Using,當然只是我的一個命名想法而已,可以聯想一下C#,用的就是using,借來而已。

Using里面寫入的當然是我需要的對象User,顧名思義,我當然寫成Using("User")了。先不說內里是怎么實現的,起碼思路是這樣。
因為不能模擬關鍵字寫成 Using User;這種起碼我是做不到了。
第二句和第三句
var u = new User(); u.show();

很正常,就是很平常的實例化與函數調用,唯一不解的是User對象哪里來的?那么當然是第一句導包的時候導入的。

 
流程就是這么個流程,那么到底能不能實現,關鍵就在第一句話。也就是說,到底能不能導包成功,而且該怎么導包。
 
從script標簽吸引靈感,對,異步加載所需要的js文件。
也就是說
Using("User");

相當於寫了一句

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

現在這么看下來,這么做有意義嗎?就為把script標簽寫成JS動態引入的?或者,只為少寫幾個字符?

當然不能,這么做毫無意義!那要怎么做?
先從效率來講。
如果一個頁面需要載入N多js文件的時候,如下
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" src="view.js"></script>
<script type="text/javascript" src="register.js"></script>
<script type="text/javascript" src="validate.js"></script>
<script type="text/javascript" src="user.js"></script>
<script type="text/javascript" src="order.js"></script>
<script type="text/javascript" src="type.js"></script>

等等等等。

是不是很嚇人,那是相當嚇人,而且后期維護需要很高的成本,有多少頁面,可能就需要修改幾個頁面。那么,當頁面只引入關鍵的幾個js文件,其他文件都采用動態載入的方式呢?
比如我們只需要載入jquery文件,然后調用
$.getScript("user.js",function(){});

這樣,我們就做到頁面文件里面只需要引入

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

即可。

那么這種寫法的壞處在哪里?看一段代碼
$.getScript("user.js",function(){ $.getScript("order.js",function(){ $.getScript("type.js",function(){ $.getScript("validate.js",function(){ // and so on.. 
 }); }); }); });

PS:用In.js的watch函數是可以避免這種情況產生的。這不在本博文的考慮范圍了。

花眼嗎?還願意去對齊代碼嗎?即便有格式化工具,你還願意將閉合括號與哪個$.getScript對應嗎?當然不願意。
那么,仿java的導包形式應聲而出。
Using("User"); Using("Order"); Using("Type"); Using("Validate"); // and so on..

或者你願意,你可以

Using("User","Type","Order","Validate",...);

寫法問題 無所謂。當然我推薦使用第一種方法,清晰。

導包之后,所有的用法不需要任何嵌套,正常使用。
var u = new User(); var o = new Order(); // and so on..

但是會提出一個問題。假如異步的加載都在Using("XXX")的時候執行,那么

Using("User"); Using("Order"); Using("Type"); Using("Validate"); // and so on..

這一段我就需要異步載入4個文件,雖然是異步的,但是未免有些麻煩?而且需要創建4個鏈接。你願意合並JS的話,也可以。而且,Using的時候我是不需要使用對象的,這個時候未免太浪費資源了?

至於這個問題,我的解決辦法就是學習hibernate,延遲加載,按需加載。
那么怎么做呢?
Using("User");

這個時候肯定是不加載,不加載做什么?當然是返回一個mock,也就是模擬對象。給用戶先用着,只有當用戶真正需要使用這個對象的時候,再去加載所需的js。也就是說

Using("User"); // 這句話執行完畢之后會創建一個User對象,當時僅僅是個mock
var u = new User(); // 這個時候用需要的是真實的User對象實例,就在這個時候去動態加載JS文件,並且返回已經實例化的User對象

大家都知道,異步加載是與當前運行的狀態不沖突的,也就是說

var u = new User();

這句話執行之后,u是一個沒有實際意義值的變量,而已。那么,怎么解決這個問題,我暫且想到的辦法,只能是采用同步策略了。只有當js加載完畢,再去執行之后的js語句,這個地方有點遺憾,而且同步可能帶來的瀏覽器假死,也是一個比較嚴重的問題,暫且不顧這些問題,希望以后能有更好的辦法解決。

那問題出來了,這么做同步,有什么優勢嗎?
我不知道有什么優勢,起碼對比異步加載,應該沒有劣勢。比如正常的異步加載為
$.getScript("user.js",function(){ var u = new User(); });

單單執行這個語句,要執行到function,本質上也是等user.js加載完畢才會執行,那么對比

var u = new User();

理論上時間應該相當,因為都是等user.js加載完畢之后才執行的。

起碼第二種看起來更像java式的代碼,不必理會其他非業務相關的代碼。
 
那么,怎么會知道需要的對象在什么地方,怎么加載進來?我能想到的就是模擬一個配置文件,為什么用配置文件,而不是像In.js用add函數或者其他框架的類似於register的函數,大概我只是想用配置文件,更像java,而且后期的修改起來也會更解耦一些吧。
Using.Config = { "User" : "/js/user"     // 可以隱去.js 因為肯定是加載JS文件了
}

整個思路大概就是這個樣子,我在其基礎上進行了一些約束,比如加入了命名空間

var u = new Using.Modules.User();

這樣可以減少一些全局變量,而且有需要的話,可以插入一些所有對象可能都具有的共性,減少創建類時的重復編碼。

當然,也還是支持不使用命名空間的。

為了解決這個約束的效力,加入了Class.create函數來進行類創建約束。
Using.Class.create("User",function(){ }).property({ }).static({ }).namespace(Using.Modules);

這里的大概意思就是

create(類名,構造函數)
property(類的屬性)
static(類的靜態屬性)
namespace(命名空間)
 
引申到此,為何不加入MVC形式?
后來我發現,要MVC,那么幾個類之間的動態維護,或者創建之時就由Using這個類來自動維護,暫時還沒想到好的解決辦法,所以沒有加入其中,只能自己創建類,自己維護了.
 
通過上面的文字,最后得到一個Using.js
然后在頁面里面就只需要引入一個
<script type="text/javascript" src="using.js"></script>

這樣接下來就可以寫

Using("jquery"); Using("User"); $("#ID").click(function(){ var user = new User(); user.name = "xx"; user.show(); });

 


免責聲明!

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



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