js動態加載腳本之實用小技巧


  最近我們公司的iClient產品需要改動,由於我們的包大概有1M了,用戶在使用的過程中如果網速不是很好的話,加載的就比較慢,用戶體驗就不好,上面要求用戶初始化的時候只有基礎包,比較小,當用戶用到哪一塊功能就加載哪塊的功能,這樣體驗上要好得多,但是我們的用戶已經有很多了,那么我們就不能讓用戶改變以前的代碼,只能讓用戶把包替換一下,這里研究了幾天研究了一種辦法和大家分享一下。對於做產品的朋友可能會有幫助吧!

  對於產品包來說,無非就是N多的類。用戶一般使用的時候都是new一個對象,然后開始使用它!比如我們有一個Person類,這里就會涉及到當瀏覽器運行到var person = new Person()這里時,其實內存里面還沒有這個類,我們並沒有在一開始就導進來,但是如果沒有的話瀏覽器肯定會報錯,那我們在new之前加一句代碼來導包,這樣不就是需要更改用戶的源代碼了嗎?肯定不可取。我們需要在瀏覽器new對象的時候把對應的類導進來,而又不改變任何源代碼,如何做到?

  我們可以在基礎包里面對每一個類寫一個假的類,但是命名空間、類名必須都是一樣的,但類里面除了構造函數什么都沒有,這樣假類就很小,基本不會使基礎包的大小改變多少,這樣在瀏覽器運行到如var person = new Person()這一句的時候至少不會報告錯誤,但是生成的對象person是假的,不可用的,我們得想辦法讓它變成真的,怎么才能讓new出的對象不是自己而是其他的對象呢?

  我嘗試了很多種辦法,比如在構造函數里面改變過this.__proto__.constructor、this.__proto__、this等手段,希望最后new出來的對象不是自身,而和new Person(真的)一樣,但是你可以調試發現沒法做到一模一樣,最后無意間發現在構造函數里面使用return就可以改變new出來的對象,如下面new Person()出一個對象。

        function Person()
        {
            return new Date();
        }

  你會發現new出來的不是Person的對象,而是一個Date對象,而且和new Date()出來的對象一模一樣,這是js這門語言故意這樣設計吧!也不知道最開始的目的是啥!如果使用return;或者return null;最后new出來的對象還是本身。這樣第一個問題就解決了,可以new出一個非自身的對象。

  繼續討論,現在我們new出來的對象需要時真的那個類,而不是那個假的類,但是兩個類的命名空間和類名都是一樣的,這可怎么辦,其實大家都知道所有的類無非就是window的屬性而已,其實都是指針,我把指向的部分改變后不久實現了嗎?

  我們先需要寫一個真的類,創建一個Person.js文件,打開后寫入如下代碼:

function Person(name,age){
    this.name =  name;
    this.age = age;
    this.getName = function(){
        return this.name;
    }
    this.getAge = function(){
        return this.age;
    }
}

  這是一個真的類,有name和age兩個屬性以及getName()和getAge()兩個方法。在在同樣的文件夾下創建一個html文件,代碼如下:

<html>
<head>
    <title></title>
    <script type="text/javascript" src="loadJS.js"></script>
    <script type="text/javascript">
        function init()
        {
            var person = new Person("Bill",23);
            var name = person.getName();
            var age = person.getAge();
            alert(name + "_" + age);
        }
        function Person(name,age)
        {
            loadJS("idPerson","Person.js");
            return  new Person(name,age);
        }
    </script>
</head>
<body>
    <button onclick="init()">測試</button>
</body>
</html>

  這里有一個loadJS.js文件,這是一個動態同步加載js文件的一個包,我自己寫的,很簡單,里面的內容詳見《js動態加載腳本》里面的第六種方法里有源代碼,其實就一個方法loadJS(id,url)。上面代碼已經有一個假的Person存在了,里面有兩句代碼,第一句是加載真的Person,第二句是返回一個Person對象,當我們調試的時候你會驚奇的發現,當真的Person加載進來后Person這個類就變成了真的類,而假的類在new以后就沒有了,因為沒有指針指向它了,它接下來就會被回收機制給回收掉,new玩后發現person就成為了真的那個Person的對象,當你再次new Person()的時候發現直接就是真的Person對象了,因為已經加載過一次了。

  我們仔細思考一下,如果Person這個類用到了我們其他沒加載的類,瀏覽器也會先尋找到假的那個類,再次去加載需要的類,這就形成了一個循環,需要什么類的時候再加載什么,不會多加載任何一個多余的類。前提是你得每一個類對應一個js文件。你也可以分成多少個模塊,每個模塊里面有多個類,那么每一次去加載就會加載一個模塊,一個模塊加載進來后會替換掉其中一部分假類。無論怎么設計都很方便。

  好了,所有問題都解決了,我們需要把假的類封裝進我們的產品包,然后讓用戶把這個包替換掉,用戶不需要改變任何以前項目的源代碼,就可以做到動態加載需要的腳本。這個辦法是不是很好用?好用就幫我頂一下!


免責聲明!

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



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