[廚餘回收] 重複載入 jQuery 會有什麼問題?如何避開?

如果我們用 jQuery 在開發網頁,那麼 jQuery 應該也一定只載入一次,偏偏就有第三方合作廠商,完全沒有在管客戶是不是會出問題?檢查也不做,愛載就載,例如:6763 的站內付 2.0,用他們的 Web JS SDK 初始付款頁面的時候強制載入了 jQuery 3.4.1,如果我們的網頁本身就已經載入 jQuery 了,就會導致重複載入,那會發生什麼事?

問題

jQuery 除了選擇器之外,還有另一個很重要的功能 - extend,架構在 jQuery 之上的擴充元件,幾乎沒有不用 extend 的,而重複載入 jQuery 會導致使用 extend 的擴充元件全數失效,底下我弄個範例,分別在 $.fn.extend() 及 $.extend() 各擴充一個方法。

正常的話,瀏覽網頁應該會看到 ABC: abc 的字樣。

可是,當我們再載入一次 jQuery 之後,網頁不僅空白一片,Console 還出現錯誤訊息,告訴我們方法不存在,因為整個 jQuery 被重置了。

解決方法

目前我用的解法是「讓 jQuery 唯讀」,我們呼叫 jQuery 函式可以透過兩個全域變數 window.$window.jQuery,我利用 Object.defineProperty() 在我們自己版本的 jQuery 載入後,重新定義 window.$ 及 window.jQuery 的 get()set(),這樣 jQuery 就唯讀了。

不過這也要注意,第三方合作廠商是不是也有自己擴充元件,有的話這個解決方法就不行了,以我目前遇到的狀況是剛好沒有。

如果我是第三方合作廠商

如果是我做為第三方合作廠商,其實大可在 API 文件中講好需要 jQuery 哪一個版本?我自己就不載入了,當沒有 jQuery 可以用或不是特定版本的時候印個錯誤訊息,又或者我們自己獨立載入,與客戶的環境切開,我們來看要怎麼做?

僅檢查 jQuery

  1. 檢查有沒有 window.jQuery?有則跳至 2.,無則印出錯誤訊息。
  2. 檢查 window.jQuery 是否為特定版本?是則往下執行,無則印出錯誤訊息。

程式碼如下,相關說明寫在註解中。

(function () {
    // 動態載入 script
    var loadScript = function (src, onload) {
        var scriptElm = document.createElement("script");
        
        scriptElm.onload = onload;
        scriptElm.src = src;

        document.body.appendChild(scriptElm);
    }

    if (window.jQuery) {
        var version = window.jQuery.fn.jquery.split(".").reduce((ver, next) => ver * 10 + parseInt(next), 0);

        if (version < 350) {
            console.error("jQuery version is not 3.5.0+")
        } else {
            // 載入其他依賴 jQuery 的程式碼
            loadScript("my.js");
        }
        
    } else {
        console.error("jQuery is not loaded")
    }

})();

獨立載入,與客戶的環境切開。

  1. 檢查目前網頁中是否已有 jQuery?有則做保留還原,無則直接載入。
  2. 建立自己的 jQuery Alias,不要使用預設的 window.$ 及 window.jQuery。

底下是程式碼,相關說明寫在註解中。

(function () {
    // 動態載入 script
    var loadScript = function (src, onload) {
        var scriptElm = document.createElement("script");
        
        scriptElm.onload = onload;
        scriptElm.src = src;

        document.body.appendChild(scriptElm);
    }

    if (window.jQuery) {
        // 保留原本的 jQuery
        var __jq = window.jQuery;
        var __$ = window.$;

        // 載入 jQuery
        loadScript("https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js", function () {
            // 建立自己的 jQuery 別名
            window._chef_jQuery = window.jQuery;
            window._chef_$ = window.$;

            // 還原原本的 jQuery
            window.jQuery = __jq;
            window.$ = __$;

            // 載入其他依賴 jQuery 的程式碼
            loadScript("my.js");
        });
        
    } else {
        loadScript("https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js", function () {
            window._chef_jQuery = window.jQuery;
            window._chef_$ = window.$;
            
            loadScript("my.js");
        });
    }

})();

// my.js
console.log("my.js loaded")

// 使用自訂的 jQuery 別名
if (window._chef_jQuery) {
    console.log("_chef_jQuery load successfully");
} else {
    console.log("_chef_jQuery load failed");
}

以上,這次被 6763 - 站內付 2.0 搞到的解決方法分享給大家,希望對用 jQuery 開發網頁的朋友有一點幫助,真覺得浪費我的時間。

相關資源

C# 指南
ASP.NET 教學
ASP.NET MVC 指引
Azure SQL Database 教學
SQL Server 教學
Xamarin.Forms 教學