讀GI源碼、學JS編程——Javascript動態加載技術。

在大型RIA中,動態加載技術十分重要,畢竟幾百K甚至M級別的腳本讓用戶等待加載完了再瀏覽是不可能。大多數成熟的framework都有動態加載技術的實現,就是說先加載一個最基礎功能,然後利用動態加載技術慢慢把所有的腳本加進來,或者說需要某個功能的時候再加載某個模塊所 需要的javascript的文件。
好了不說那麼多P話了,儘快進入正題來看看GI是怎麼實現的動態加載技術。其實GI的load做的很複雜,因爲他涉及到了進度條阿等等很多亂七八糟的東西,我們就不分析那麼多東西了,來看看他最基礎的東西是如何實現的吧。GI中的動態加載有兩種,一種是用的是XMLHttpRequest來請求腳本內容,另一種則是加入一個 <script>標籤的方式來動態加入腳本以達到動態加載的功能。網上也許還有其它得方法,但其它得方法也都是根據這兩種演變來的,還是以這兩種爲基礎得。我們來看看它是如何實現的。
首先是第一種
      /** @private @jsxobf-clobber */
      ClassLoader_prototype.loadJSFileSync 
= function(strURI) {
        
var req = new jsx3.net.Request();
        req.open(
"GET", strURI, false);
        req.send();
            
        
if (req.getStatus() == jsx3.net.Request.STATUS_OK) {
          
var script = req.getResponseText();
          jsx3.eval(script);
          
return true;
        }

        
return false;
      };
呵呵,XMLHttpRequest的GET請求就可以吧js文件拿下來,然後用eval執行所有的腳本,這樣就達到了加載腳本的功能了。方法也很簡單,也就不用多介紹什麼了吧。不過我記着有人說過js必須要UTG-8格式存的,但測試了一下,不用好像也可以。
我們看在package。Js文件裏面有個有意思的方法
  /**
   * Ensures that one or more classes is available before this method returns. Any class that fails to load will
   * throw an error. Only classes that can be found by the system class loader may be loaded in this manner.
   *
   * @param strClass {String} the fully-qualified names of the classes to load.
   * @since 3.2
   
*/
  jsx3.require 
= function(strClass) {
    
for (var i = 0; i < arguments.length; i++) {
      
var className = arguments[i];
      className 
= jsx3._REQUIRE_MAP[className] || className;
      
if (jsx3.Class.forName(className) == null)
        jsx3.CLASS_LOADER.loadClass(className);
    }
  };

需要說明的是jsx3.ClASS_LOADER.loadClass()方法中其實就是調用了loadJSFileSync()方法,這個方法就是在調用類之前如果該類沒有被加載將會在被load一次做到需要什麼才用什麼,不會把所有Javascipt都加載進來。
然後我們再來看第二種方法,添加標籤的方式來load腳本
      /** @private @jsxobf-clobber */
      ClassLoader_prototype.loadScript 
= function(strSrc, strId) {
        
// instance a new DOM element
        var element = document.createElement("script");
        element.src 
= strSrc;
        element.type 
= 'text/javascript';
        element.id 
= strId;
        element.language 
= 'javascript';
        
        
// set up onload handler
        var me = this;
        
if (this.IE) {
          element.onreadystatechange 
= function() { 
            
var state = this.readyState;
            
if (state == "loaded" || state == "interactive" || state == "complete") {
              
this.onreadystatechange = null;
              me._loaded[strSrc] 
= true;
              me._publish({subject:
"load", type:"script", src:strSrc});
            }
          };
        } 
else if (this.MOZ || this.KON) {
          element.onload 
= function() { 
            element.onload 
= null;
            me._loaded[strSrc] 
= true;
            me._publish({subject:
"load", type:"script", src:strSrc}); 
          };
        }
        
        element.jsxid 
= strSrc;
        
        
// bind the element to the browser DOM to begin loading the resource
        document.getElementsByTagName("head")[0].appendChild(element);
      };

呵呵,相信大家都能看懂吧,就是在head標籤中加入了script標籤,src當然就是重點了,而如何判斷腳本加載結束,也明確的告訴我們,在IE下用onreadystatechange,在Firefox下用onload。呵呵,好像很簡單吧。
到這裏,我突然想到一個問題,script標籤好像功能很強大啊,竟然可以用來讀服務器上的Javascript文件,跟XMLHttpRequest有同樣的功能啊,看來這個東西可以被我們來利用一下了,做點手腳也許會有不同的效果哦,來看。
首先我們寫一個Handlers用來模擬一個Javascript文件,然後用這個handler來生成返回的內容,
      <httpHandlers>
        
<add verb="*" type="JsTest.JsHandler" path="demo2.js"/>
      
</httpHandlers>

    public class JsHandler:IHttpHandler,IRequiresSessionState
    {
        
public void ProcessRequest(HttpContext context)
        {
            
string action = context.Request["action"].ToString();
            context.Response.Write(
"alert(/"hello world  " + action + "/");");
        }
}

這個Handler中我只是返回了一段alert,呵呵,下面用script來加載他吧,剛纔看到的一樣,只是script中src我們做了點手腳,嘿嘿指向的是demo2.js?action=city22,哈哈看到了吧,就是個GET訪問方式啊!
不過有人肯定該問了,這個有什麼用XMLHttpRequest已經很好用了啊,幹嘛在來個這東西。我感覺這東西在一定的領域還是能發揮作用的。XMLHttpRequest不能垮站訪問,這是個問題,也就是說你在www.a.net/index.html上寫了一段XMLHttpRequest不能調用www.b.net上的任何東西,即使改動document.domian 也不可以,唉多可惜。當然了Iframe給我們解決了這個問題,但是script標籤又給了我們新的選擇,我們完全可以模擬open(),send(),等這些方法,返回的腳本中使用變量作爲返回內容來模擬responseText。看來跨站問題又有了新的解決思路了。以後script標籤值得我們去深入研究一下咯。

 

這種功能也可以實現網站內容的外部發布
在handle裏可以把script的東西都寫了:)

不過我記着有人說過js必須要UTG-8格式存的,但測試了一下,不用好像也可以。

如果不用utf-8的格式存儲js文件,偶爾在有漢字(包括常量、註釋等)的情況下會導致js的各種運行錯誤、異常;我曾經被這個問題鬱悶了一整天,後來才發現js文件使用ANSI編碼保存的。

js和html頁面的編碼一樣應該就ok了,不一定要utf8

eval執行所有的腳本,這一步會不會很慢啊!

《script src='xxxx.aspx?action=xxx'》《/script》不就行? 用個handler沒什麼用處,只是名字看起來象是js罷了.

window.onload=function()
{
    
var script=document.createElement("script");
    script.type
='text/javascript';
    script.language
='javascript';
    script.src
="demo2.js?action=city22";
    document.getElementsByTagName(
"head")[0].appendChild(script);
}
測試成功,哈,看來還真是能模擬一個XMLHttpRequest了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章