動態載入JS函數

来源:https://www.cnblogs.com/jasonxu19900827/archive/2018/08/21/9509171.html
-Advertisement-
Play Games

一般性的,當我們需要載入js文件的時候都會使用script標簽來實現,類似於如下代碼: 代碼如下: <script type="text/javascript" src="example.js"></script> 但是直接使用script標簽來載入js文件會有如下一些缺點: 1.嚴格的讀取順序。由 ...


一般性的,當我們需要載入js文件的時候都會使用script標簽來實現,類似於如下代碼:

代碼如下:
<script type="text/javascript" src="example.js"></script>


但是直接使用script標簽來載入js文件會有如下一些缺點:

1.嚴格的讀取順序。由於瀏覽器按照<script>在網頁中出現的順序,讀取Javascript文件,然後立即運行,導致在多個文件互相依賴的情況下,依賴性最小的文件必須放在最前面,依賴性最大的文件必須放在最後面,否則代碼會報錯。

2.性能問題。瀏覽器採用"同步模式"載入<script>標簽,也就是說,頁面會"堵塞"(blocking),等待javascript文件載入完成,然後再運行後面的HTML代碼。當存在多個<script>標簽時,瀏覽器無法同時讀取,必須讀取完一個再去讀取另一個,造成讀取時間大大延長,頁面響應緩慢。

這個時候我們就會想到去動態載入JS,動態載入js的實現方法類似於如下代碼

代碼如下:
/*
*@desc:動態添加script
*@param src:載入的js文件的地址
*@param callback:js文件載入完成之後需要調用的回調函數
*@demo:
addDynamicStyle('http://webresource.c-ctrip.com/code/cquery/LABjs/LAB.js', function () {
    alert('攜程伺服器上的lab.js載入完成')
});
*/
function addDynamicJS(src, callback) {
    var script = document.createElement("script");
    script.setAttribute("type", "text/javascript");
    script.src = src[i];
    script.charset = 'gb2312';
    document.body.appendChild(script);
    if (callback != undefined) {
        script.onload = function () {
            callback();
        }
    }
}

這樣不會造成頁面堵塞,但會造成另外一個問題:這樣載入的Javascript文件,不在原始的DOM結構之中,因此在DOM-ready(DOMContentLoaded)事件和window.onload事件中指定的回調函數對它無效。

這個時候我們就會想到用一些外部函數庫來有效的管理JS載入問題。

下麵進入正題說說LAB.js

LAB.js

如果我們使用傳統的方法來載入js的話,寫的代碼一般會如下方代碼所示風格。

代碼如下:
<script src="aaa.js"></script>
    <script src="bbb-a.js"></script>
    <script src="bbb-b.js"></script>
    <script type="text/javascript">
        initAaa();
        initBbb();
    </script>
    <script src="ccc.js"></script>
    <script type="text/javascript">
        initCcc();
    </script>

如果我們使用LAB.js的話,要實現上述代碼功能,則使用如下方式

代碼如下:
<!--先載入lab.js庫-->
    <script src="http://webresource.c-ctrip.com/code/cquery/LABjs/LAB.js"></script>
    <script type="text/javascript">
        $LAB
        .script("aaa.js").wait()//不帶參數的.wait()方法表示立即運行剛纔載入的Javascript文件
        .script("bbb-a.js")
        .script("bbb-b.js")//依次載入aaa.js bbb-a.js bbb-b.js  然後執行initAaa initBbb
        .wait(function () {//帶參數的.wait()方法也是立即運行剛纔載入的Javascript文件,但是還運行參數中指定的函數。
            initAaa();
            initBbb();
        })
        .script("ccc.js")//再載入ccc.js 載入完成ccc.js之後執行initCcc方法
        .wait(function () {
            initCcc();
        });
    </script>

可以同時運行多條$LAB鏈,但是它們之間是完全獨立的,不存在次序關係。如果你要確保一個Javascript文件在另一個文件之後運行,你只能把它們寫在同一個鏈操作之中。只有當某些腳本是完全無關的時候,你才應該考慮把它們分成不同的$LAB鏈,表示它們之間不存在相關關係。

一般性的使用示例

代碼如下:
$LAB
.script("script1.js") // script1, script2, and script3 相互不依賴, 可以按照任意的順序執行
.script("script2.js")
.script("script3.js")
.wait(function(){
    alert("Scripts 1-3 are loaded!");
})
.script("script4.js") //必須等待script1.js,script2.js,script3.js執行完畢之後才能執行
.wait(function(){script4Func();});
代碼如下:
$LAB
.script("script.js")   
.script({ src: "script1.js", type: "text/javascript" })
.script(["script1.js", "script2.js", "script3.js"])
.script(function(){
    // assuming `_is_IE` defined by host page as true in IE and false in other browsers
    if (_is_IE) {
        return "ie.js"; // only if in IE, this script will be loaded
    }
    else {
        return null; // if not in IE, this script call will effectively be ignored
    }
})

在控制台看LAB.js的載入信息

如果你想調試或者說在控制台看各個js載入信息的話,可以使用$LAB.setGlobalDefaults 方法,具體使用請看代碼示例。

代碼如下:
<!--先載入攜程的LAB庫  lab.js在網上也可以下載-->
    <script type="text/javascript" src="http://webresource.c-ctrip.com/code/cquery/LABjs/LAB.js" charset="gb2312"></script>

    <script type="text/javascript">

        $LAB.setGlobalDefaults({ Debug: true }) //打開調試

        $LAB
            //第一個執行鏈
           .script('http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.0/jquery.min.js')
           .script('http://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js')

           //第二個執行鏈
           .wait(function () {
               //console.log(window.$)
               //console.log(window._)
           })

           //第三個執行鏈
           .script('http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.1.1/js/bootstrap.min.js')
           .script('http://cdnjs.cloudflare.com/ajax/libs/fancybox/2.1.5/jquery.fancybox.pack.js')

           //第四個執行鏈
           .wait(function () {
               // console.log(plugin1Function)
               // console.log(plugin2Function)
           })

           //第五個執行鏈
           .script('js/aaa.js')
           .script('js/bbb.js')

           //第六個執行鏈
           .wait(function () {
               // console.log(module1Function)
               // console.log(module2Function)
           })
    </script>

這個時候打開控制台,看信息,如下圖所示:

 

實例

  //載入大的背景圖,不能等背景圖先顯示出來再執行html代碼

  <head>

  {insert_scripts files='LAB.min.js'}

  </head>

  <body>

  <script>

  $LAB.script("xxx/js/sign.min.js")

  .wait() //立即執行

  </script>

  </body>

 

  //除了背景圖還有輪換圖,目前只用到這兩種

  <html>

  <head>

  {insert_scripts files='LAB.min.js'}

  </head>

  <body>

  <script>

  $LAB.script("xxx/xxx/js/jquery.flexslider.min.js")

  .wait(function(){

  //banner 滾動

  $('#js_banner').flexslider({
                namespace:"",
                animation: "fade",
                selector: ".slides > li",
                pauseOnAction:false,
                controlNav:true,
                slideshowSpeed: 5000
            });    
    
            $('#whatsnew_pros').flexslider({
                namespace:"",
                animation: "slide",
                selector: ".slides > li",
                itemWidth: 150,
                pauseOnAction:false,
                controlNav:false,
                animationLoop: true,
                slideshow:false,  
                animationSpeed:50,
                minItems: 4,
                maxItems: 5
            });
            $('#seller_pros').flexslider({
                namespace:"",
                animation: "slide",
                selector: ".slides > li",
                itemWidth: 150,
                pauseOnAction:false,
                controlNav:false,
                animationLoop: true,
                slideshow:false,  
                animationSpeed: 50,
                minItems: 4,
                maxItems: 5
            });
            $('#specials_pros').flexslider({
                namespace:"",
                animation: "slide",
                selector: ".slides > li",
                itemWidth: 150,
                pauseOnAction:false,
                controlNav:false,
                animationLoop: true,
                slideshow:false,  
                animationSpeed: 50,
                minItems: 4,
                maxItems: 5
            });
            
            $("#seller_pros").hide();
            $("#specials_pros").hide();
            $("#whatsnew_pros").show();

  })

  </script>

  </body>
  </html>

JavaScript文件載入器LABjs API詳解

  在《高性能JavaScript》一書中提到了LABjs這個用來載入JavaScript文件的類庫,LABjs是Loading And Blocking JavaScript的縮寫,顧名思義,載入和阻塞JavaScript,而它的API script()和wait()則優雅地實現了這兩個功能,我在高性能JavaScript 載入和執行一文中也簡單講解了這兩個核心API的用法。當然,LABjs還有更多的API,本文用實例講解下LABjs其他API。

$LAB.setGlobalDefaults() & $LAB.setOptions()

  兩者所能設置的參數完全一致,不同的是,前者是全局設置,作用在所有的$LAB鏈上;後者出現在某條鏈的開頭位置(後面接script()、wait()等),該設置只作用在這條鏈上。該參數可以是一個包含多個鍵值對的對象

  • AlwaysPreserveOrder

  一個布爾值(預設false),如果設置為true,則每個script()後都會預設設置一個wait(),使得鏈上的腳本一個個執行。

複製代碼
$LAB
  .setOptions({AlwaysPreserveOrder:true}) // tells this chain to implicitly "wait" on 
                                          // execution (not loading) between each script
  .script("script1.js") // script1, script2, script3, and script4 *DO* depend on each 
  .script("script2.js") // other, and will execute serially in order after all 4 have have
  .script("script3.js") // loaded in parallel
  .script("script4.js")
  .wait(function(){script4Func();});
複製代碼
  • UseLocalXHR

  一個布爾值(預設true),如果是true的話,LABjs會用XHR Ajax去預載入同域的腳本文件。值得註意的是,只應用在老式的Webkit瀏覽器(那些既不能使用ordered-async也不能實現真正的預載入的瀏覽器),而且同域的情況下,該設置才起效(不然直接無視)

  • CacheBust & AllowDuplicates

  LABjs對於緩存有一些奇怪的處理(關於緩存,可以參考我前面的一篇文章瀏覽器緩存機制淺析),比如如下代碼:

$LAB.script('index.js');

  很簡單對吧?第一次載入,沒有任何問題,HTTP200從server端下載。但是f5後:

  (2015-8-3 這個問題有點詭異,有時HTTP304,有時HTTP200from cache 我也在github上詢問了作者 LABjs reads from cache when f5,回覆的大概意思是cache和labjs沒有任何關係,只和伺服器和瀏覽器設置有關)

  居然是從緩存讀取的!這就是說服務端的改動,對它不起效果!而通常情況下f5後是會向伺服器發送請求的,如果服務端文件沒有修改返回HTTP304讀取緩存,如果修改了文件直接load新的。針對這個問題我們可以使用CacheBust選項:

$LAB.setGlobalDefaults({CacheBust: true})
$LAB.script('index.js');

  這樣就能保證每次都從服務端讀取文件(從不讀取緩存)。

  還有一個問題,對於幾個相同的請求,LABjs預設只會執行一次:

$LAB.script('index.js').script('index.js');
$LAB.script('index.js');

  實際上index.js這個文件只執行了一次!如果index.js里的代碼是列印hello world,也就是說只會被列印一次。如何做到能列印三次?用AllowDuplicates:

$LAB.setGlobalDefaults({AllowDuplicates: true})
$LAB.script('index.js').script('index.js');
$LAB.script('index.js');

  實際上上面的代碼,儘管會執行三次index.js,但是請求只有一次,其他兩個都是緩存讀取,而且如前面所說,如果服務端修改了,也會從緩存讀取,這太可怕了。所以AllowDuplicates可以配合CacheBust使用

$LAB.setGlobalDefaults({AllowDuplicates: true, CacheBust: true})
$LAB.script('index.js').script('index.js');
$LAB.script('index.js');

  其實就是帶了一串代表請求唯一的字元串,這在ajax請求中很常見。

  • BasePath

  一個字元串(預設空串),會將這個字元串加在每個script()里的URL的最前面。

  • Debug

  一個布爾值(預設false),如果開啟debug選項的話,會在控制台列印信息,需要註意的是,只有使用了LAB-debug.min.js或者LAB.src.js該選項才work。

$LAB.script() & $LAB.wait()

  script()里的參數可以是很多形式,比如字元串(文件的相對路徑或者絕對路徑)、對象(src、type、charset src必須)、數組或者方法(或者前者們的組合),更多demo可以參考Example 8 below。前三者很好理解,這裡簡單提下參數為function的情況,當script()里的參數是個匿名的function的時候,該function會立即執行,它可以return一個值,而該值必須是以上說的string、object或者array形式,相當於給該script()賦值了。

複製代碼
$LAB
  .script(function(){
    // assuming `_is_IE` defined by host page as true in IE and false in other browsers 
    if (_is_IE) {
      return "ie.js"; // only if in IE, this script will be loaded
    }
    else {
      return null; // if not in IE, this script call will effectively be ignored
    }
  })
  .script("script1.js")
  .wait();
複製代碼

$LAB.queueScript() & $LAB.queueWait() & $LAB.runQueue() & $LAB.sandbox()

  script()和wait()會使得腳本立即執行(除非設置定時器),但是queueScript()和queueWait()能使得腳本在任意時刻執行,執行的時候帶上runQueue()就行了。

複製代碼
var a = $LAB.queueScript('index.js').queueWait(function() {
  console.log('hello world');
});

setTimeout(function() {
  a.runQueue()
}, 1000);
複製代碼

  如上腳本就能在1000ms後執行,這樣的效果貌似script()配合定時器也能實現,但是在未來某一不確定時刻執行就不行了(比如說一段指定代碼後)。如果有兩個鏈要在未來某時刻執行呢?

複製代碼
var a = $LAB.queueScript('index.js').queueWait(function() {
  console.log('hello world');
});

setTimeout(function() {
  a.runQueue()
}, 1000);

var b = $LAB.queueScript('index2.js').queueWait(function() {
  console.log('hello world');
});

setTimeout(function() {
  b.runQueue()
}, 2000);
複製代碼

  如上代碼並沒能得到預想的結果(實際上1000ms後一起輸出),這時就需要用sandbox()創建一個新的實例。

複製代碼
var a = $LAB.queueScript('index.js').queueWait(function() {
  console.log('hello world');
});

setTimeout(function() {
  a.runQueue()
}, 1000);

var b = $LAB.sandbox().queueScript('index2.js').queueWait(function() {
  console.log('hello world');
});

setTimeout(function() {
  b.runQueue()
}, 2000);
複製代碼

$LAB.noConflict() 

  使用noConflict()會將當前版本的LABjs回滾到舊的版本。(2015-08-04 這個解釋應該是錯的)

 

  read more from  LAB documentation

github LAB.js 2.0.3及以下版本版本https://github.com/getify/LABjs

       3.0目前正在進行重寫中https://github.com/getify/LABjs/tree/v3.0

參考自:https://www.jb51.net/article/61488.htm

    https://www.cnblogs.com/zichi/p/4689008.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 這裡講講SqlServer的隱式事務。(英文Implicit:含蓄的;暗示的;盲從的;) 隱式事務無需顯示開始:不用 Begin Transaction,必須顯示結束:以 Commit Transaction 或者 Rollback Transaction 方式結束。 語句迭代迭代:SET IMPL ...
  • 最近很多人都想學習大數據開發,但是卻不知道如何開始學習,今天軟妹子專門整理了一份針對大數據初學者的大數據開發學習路線。 下麵分十個章節來說明大數據開發要學習的內容: 以上就是一個大數據新手,想要學會大數據開發,需要學習的內容,大數據學習是一個持續的過程,只要用心學,沒有學不會的東西哦! 推薦一個大數 ...
  • Oracle資料庫的管理相較於其他資料庫,是比較麻煩的,客戶端工具的安裝都要花一些時間,目前有一款treesoft軟體,通過網頁的方式管理Oracle。 功能包括:資料庫的展示,庫表的展示,表欄位結構的展示, SQL語句的線上編輯批量執行,表結構的線上設計維護,數據的線上編輯維護,數據可視化,數據定 ...
  • Android系統的運行時庫層代碼是用C++來編寫的,用C\++ 來寫代碼最容易出錯的地方就是指針了,一旦使用不當,輕則造成記憶體泄漏,重則造成系統崩潰。不過系統為我們提供了智能指針,避免出現上述問題,本文將系統地分析Android系統智能指針(輕量級指針、強指針和弱指針)的實現原理。 在使用C++來 ...
  • TextView EditText Button imageView Spinner下拉列表 RadioGroup(覆選框) / Checkbox(單選框) ProgressBar進度條 RatingBar星級控制項 SeekBar進度條控制項 ...
  • "Android項目刮刮獎詳解(一)" 前言 上期我們簡單地實現了一個畫板的功能,用戶可以在上面亂寫亂畫,其實,刮刮獎也是如此,用戶刮獎的時候也是亂寫亂畫的。 刮刮獎原理 一共有兩層畫布,底層畫布存放中獎信息的圖片,上層畫布則是一個遮蓋層,我們將底層畫布成為信息層,上層畫布稱作為遮蓋層。 用戶再遮蓋 ...
  • Element.getBoundingClientRect()返回元素的大小及相對於視窗的位置 語法: rectObject=object.getBoundingClientRect(); 返回值是一個DOMRect對象,即DOMRect={x:scrollLeft,y:scrollY,width: ...
  • css sprites:精靈圖(雪碧圖):把一堆小圖片整合在一張大圖上,通過背景圖片相關設置(背景圖片、背景圖是否重覆、背景圖定位),顯示圖片,減輕伺服器對圖片的請求數量 優點: 1、減少網頁的HTTP請求,提高頁面性能 2、圖片命名上的困擾 3、更換風格方便 缺點: 1、必須限定容器大小,符合背景 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...