簡體   English   中英

使用 Google 托管的 jQuery 的最佳方法,但退回到我在 Google 上的托管庫失敗

[英]Best way to use Google's hosted jQuery, but fall back to my hosted library on Google fail

嘗試在 Google (或其他 Google 托管的庫)上加載托管的 jQuery ,但如果 Google 嘗試失敗,則加載我的 jQuery 副本的好方法是什么?

我並不是說谷歌是脆弱的。 在某些情況下,Google 副本被阻止(例如,顯然在伊朗)。

我會設置一個計時器並檢查 jQuery 對象嗎?

兩個副本都通過會有什么危險?

並不是真的在尋找“只使用谷歌的”或“只使用你自己的”之類的答案。 我理解這些論點。 我也了解用戶可能會緩存 Google 版本。 我正在考慮一般雲的回退。


編輯:這部分添加了...

由於 Google 建議使用 google.load 加載 ajax 庫,並且在完成后執行回調,我想知道這是否是序列化此問題的關鍵。

我知道這聽起來有點瘋狂。 我只是想弄清楚它是否可以以可靠的方式完成。


更新:jQuery 現在托管在 Microsoft 的 CDN 上。

http://www.asp.net/ajax/cdn/

你可以這樣實現:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>

<script>
       window.jQuery || document.write('<script src="/path/to/your/jquery"><\/script>');
</script>

這應該在您頁面的<head>並且任何 jQuery 就緒事件處理程序都應該在<body>以避免錯誤(盡管它不是萬無一失的!)。

使用 Google 托管的jQuery 的另一個原因是,在某些國家/地區,Google 的域名是被禁止的。

迄今為止最簡單、最干凈的方法:

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="path/to/your/jquery"><\/script>')</script>

這似乎對我有用:

<html>
<head>
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
// has the google object loaded?
if (window.google && window.google.load) {
    google.load("jquery", "1.3.2");
} else {
    document.write('<script type="text/javascript" src="http://joecrawford.com/jquery-1.3.2.min.js"><\/script>');
}
window.onload = function() {
    $('#test').css({'border':'2px solid #f00'});
};
</script>
</head>
<body>
    <p id="test">hello jQuery</p>
</body>
</html>

它的工作方式是使用調用http://www.google.com/jsapigoogle對象加載到window對象上。 如果該對象不存在,我們假設對 Google 的訪問失敗。 如果是這種情況,我們使用document.write加載本地副本。 (在這種情況下,我使用的是我自己的服務器,請使用您自己的服務器進行測試)。

我還測試window.google.load是否存在 - 我還可以進行typeof檢查,以查看事物是否是對象或函數。 但我認為這可以解決問題。

這只是加載邏輯,因為自從我發布了我正在測試的整個 HTML 頁面后,代碼突出顯示似乎失敗了:

if (window.google && window.google.load) {
    google.load("jquery", "1.3.2");
} else {
    document.write('<script type="text/javascript" src="http://joecrawford.com/jquery-1.3.2.min.js"><\/script>');
}

雖然我必須說,我不確定如果這是您的網站訪問者所關心的問題,您是否應該擺弄Google AJAX 庫 API

有趣的事實我最初嘗試在各種版本中為此使用 try..catch 塊,但找不到像這樣干凈的組合。 我很想看看這個想法的其他實現,純粹是作為一個練習。

如果您的網站上嵌入了 Modernizr.js,則可以使用內置的 yepnope.js 異步加載腳本 - 其中包括 jQuery(帶回退)。

Modernizr.load([{
    load : '//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js'
},{
    test : window.jQuery,
    nope : 'path/to/local/jquery-1.7.2.min.js',
    both : ['myscript.js', 'another-script.js'],
    complete : function () {
        MyApp.init();
    }
}]);

這將從 Google-cdn 加載 jQuery。 然后檢查jQuery是否加載成功。 如果不是(“nope”),則加載本地版本。 還加載了您的個人腳本 - “兩者”表示加載過程是獨立於測試結果啟動的。

當所有加載過程完成時,將執行一個函數,在“MyApp.init”的情況下。

我個人更喜歡這種異步腳本加載方式。 由於我在構建站點時依賴於 Modernizr 提供的功能測試,因此無論如何我都將其嵌入到站點中。 所以實際上沒有開銷。

這里有一些很好的解決方案,但我想在本地文件方面更進一步。

在 Google 確實失敗的情況下,它應該加載本地源,但服務器上的物理文件不一定是最佳選擇。 我提出這個問題是因為我目前正在實施相同的解決方案,只是我想回退到由數據源生成的本地文件。

我這樣做的原因是,當涉及到跟蹤我從 Google 加載的內容與我在本地服務器上加載的內容時,我想有所保留。 如果我想更改版本,我會希望我的本地副本與我嘗試從 Google 加載的內容保持同步。 在一個有很多開發人員的環境中,我認為最好的方法是自動化這個過程,這樣所有人只需更改配置文件中的版本號。

這是我提出的理論上應該可行的解決方案:

  • 在應用程序配置文件中,我將存儲 3 項內容:庫的絕對 URL、JavaScript API 的 URL 和版本號
  • 編寫一個類來獲取庫本身的文件內容(從應用程序配置中獲取 URL),將其與名稱和版本號一起存儲在我的數據源中
  • 編寫一個處理程序,將我的本地文件從數據庫中拉出並緩存文件,直到版本號更改。
  • 如果它確實發生了變化(在我的應用程序配置中),我的類將根據版本號提取文件內容,將其保存為我的數據源中的新記錄,然后處理程序將啟動並提供新版本。

理論上,如果我的代碼編寫正確,我需要做的就是更改我的應用程序配置中的版本號,然后 viola! 您有一個自動化的后備解決方案,並且您不必在服務器上維護物理文件。

大家覺得呢? 也許這有點矯枉過正,但它可能是維護 AJAX 庫的一種優雅方法。

橡子

if (typeof jQuery == 'undefined') {
// or if ( ! window.jQuery)
// or if ( ! 'jQuery' in window)
// or if ( ! window.hasOwnProperty('jQuery'))    

  var script = document.createElement('script');
  script.type = 'text/javascript';
  script.src = '/libs/jquery.js';

  var scriptHook = document.getElementsByTagName('script')[0];
  scriptHook.parentNode.insertBefore(script, scriptHook);

}

在您嘗試從 CDN 中包含 Google 的副本之后。

在 HTML5 中,您不需要設置type屬性。

您還可以使用...

window.jQuery || document.write('<script src="/libs/jquery.js"><\/script>');

您可能希望使用本地文件作為最后的手段。

目前看來 jQuery 自己的 CDN 不支持 https。 如果是這樣,那么您可能想先從那里加載。

所以這里的順序是:Google CDN => Microsoft CDN => 您的本地副本。

<!-- load jQuery from Google's CDN -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script> 
<!-- fallback to Microsoft's Ajax CDN -->
<script> window.jQuery || document.write('<script src="//ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.3.min.js">\x3C/script>')</script> 
<!-- fallback to local file -->
<script> window.jQuery || document.write('<script src="Assets/jquery-1.8.3.min.js">\x3C/script>')</script> 

有條件地加載最新/舊版 jQuery 版本和回退:

<!--[if lt IE 9]>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
    <script>window.jQuery || document.write('<script src="/public/vendor/jquery-legacy/dist/jquery.min.js">\x3C/script>')</script>
<![endif]-->
<!--[if gte IE 9]><!-->
    <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
    <script>window.jQuery || document.write('<script src="/public/vendor/jquery/dist/jquery.min.js">\x3C/script>')</script>
<!--<![endif]-->

由於谷歌的禁止問題,我更喜歡使用微軟的 cdn http://www.asp.net/ajaxlibrary/cdn.ashx

  • 第 1 步:jQuery 加載失敗了嗎? (檢查jQuery變量)

如何在 JavaScript 中檢查未定義的變量

  • 第 2 步:動態導入(備份)javascript 文件

如何在另一個 JavaScript 文件中包含一個 JavaScript 文件?

更新:
結果證明這個答案是錯誤的。 請參閱評論以獲得真正的解釋。


你們中的大多數問題都得到了回答,但至於最后一部分:

兩個副本都通過會有什么危險?

真的沒有。 您會浪費帶寬,下載第二個無用副本可能會增加一些毫秒,但如果它們都通過,則不會造成實際傷害。 當然,您應該使用上述技術避免這種情況。

對於那些使用 ASP.NET MVC 5 的人,請在您的 BundleConfig.cs 中添加此代碼以啟用 jquery 的 CDN:

bundles.UseCdn = true;
Bundle jqueryBundle = new ScriptBundle("~/bundles/jquery", "//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js").Include("~/Scripts/jquery-{version}.js");
jqueryBundle.CdnFallbackExpression = "window.jQuery";
bundles.Add(jqueryBundle);

這里有一個很好的解釋!

還實現了加載延遲和超時!

http://happyworm.com/blog/2010/01/28/a-simple-and-robust-cdn-failover-for-jquery-14-in-one-line/

我認為應該將最后一個 < 轉義為字符串中的 \\x3C 。 當瀏覽器看到 時,它認為這是腳本塊的結尾(因為 HTML 解析器對 JavaScript 一無所知,所以它無法區分出現在字符串中的內容和實際用於結束腳本的內容元素)。 因此,直接出現在 HTML 頁面內的 JavaScript 中將(在最好的情況下)導致錯誤,並且(在最壞的情況下)是一個巨大的安全漏洞。

<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.0.0.min.js"></script>
<script>window.jQuery || document.write('<script src="js/jquery-2.0.0.min.js">\x3C/script>')</script>

我做了一個 Gist,如果它尚未加載,它應該動態加載 jQuery,如果源失敗,它會繼續回退(從許多答案拼接在一起): https : //gist.github.com/tigerhawkvok/9673154

請注意,我計划更新 Gist,但不更新這個答案,這是值得的!

/* See https://gist.github.com/tigerhawkvok/9673154 for the latest version */
function cascadeJQLoad(i) { // Use alternate CDNs where appropriate to load jQuery
    if (typeof(i) != "number") i = 0;
    // the actual paths to your jQuery CDNs
    var jq_paths = [
        "ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js",
        "ajax.aspnetcdn.com/ajax/jQuery/jquery-2.1.0.min.js"
    ];
    // Paths to your libraries that require jQuery
    var dependent_libraries = [
        "js/c.js"
    ];
    if (window.jQuery === undefined && i < jq_paths.length) {
        i++;
        loadJQ(jq_paths[i], i, dependent_libraries);
    }
    if (window.jQuery === undefined && i == jq_paths.length) {
        // jQuery failed to load
        // Insert your handler here
    }
}

/***
 * You shouldn't have to modify anything below here
 ***/

function loadJQ(jq_path, i, libs) { //load jQuery if it isn't already
    if (typeof(jq_path) == "undefined") return false;
    if (typeof(i) != "number") i = 1;
    var loadNextJQ = function() {
        var src = 'https:' == location.protocol ? 'https' : 'http';
        var script_url = src + '://' + jq_path;
        loadJS(script_url, function() {
            if (window.jQuery === undefined) cascadeJQLoad(i);
        });
    }
    window.onload = function() {
        if (window.jQuery === undefined) loadNextJQ();
        else {
            // Load libraries that rely on jQuery
            if (typeof(libs) == "object") {
                $.each(libs, function() {
                    loadJS(this.toString());
                });
            }
        }
    }
    if (i > 0) loadNextJQ();
}

function loadJS(src, callback) {
    var s = document.createElement('script');
    s.src = src;
    s.async = true;
    s.onreadystatechange = s.onload = function() {
        var state = s.readyState;
        try {
            if (!callback.done && (!state || /loaded|complete/.test(state))) {
                callback.done = true;
                callback();
            }
        } catch (e) {
            // do nothing, no callback function passed
        }
    };
    s.onerror = function() {
        try {
            if (!callback.done) {
                callback.done = true;
                callback();
            }
        } catch (e) {
            // do nothing, no callback function passed
        }
    }
    document.getElementsByTagName('head')[0].appendChild(s);
}

/*
 * The part that actually calls above
 */

if (window.readyState) { //older microsoft browsers
    window.onreadystatechange = function() {
        if (this.readyState == 'complete' || this.readyState == 'loaded') {
            cascadeJQLoad();
        }
    }
} else { //modern browsers
    cascadeJQLoad();
}

谷歌托管的 jQuery

  • 如果您關心舊瀏覽器,主要是 IE9 之前的 IE 版本,這是最廣泛兼容的 jQuery 版本
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
  • 如果你不關心 oldIE,這個更小更快:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>

備份/后備計划!

  • 無論哪種方式,您都應該使用回退到本地,以防萬一 Google CDN 失敗(不太可能)或在您的用戶訪問您網站的位置(可能性稍大)(例如伊朗或有時是中國)中被阻止。
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script>if (!window.jQuery) { document.write('<script src="/path/to/your/jquery"><\/script>'); }
</script>

參考: http : //websitespeedoptimizations.com/ContentDeliveryNetworkPost.aspx

if (typeof jQuery == 'undefined')) { ...

要么

if(!window.jQuery){

如果未加載 cdn 版本將不起作用,因為瀏覽器將運行此條件並且在此期間仍在下載需要 jQuery 的其余 javascript 並返回錯誤。 解決方案是通過該條件加載腳本。

    <script src="http://WRONGPATH.code.jquery.com/jquery-1.4.2.min.js" type="text/javascript"></script><!--  WRONGPATH for test-->
  <script type="text/javascript">
  function loadCDN_or_local(){
    if(!window.jQuery){//jQuery not loaded, take a local copy of jQuery and then my scripts
      var scripts=['local_copy_jquery.js','my_javascripts.js'];
      for(var i=0;i<scripts.length;i++){
      scri=document.getElementsByTagName('head')[0].appendChild(document.createElement('script'));
      scri.type='text/javascript';
      scri.src=scripts[i];
    }
  }
  else{// jQuery loaded can load my scripts
    var s=document.getElementsByTagName('head')[0].appendChild(document.createElement('script'));
    s.type='text/javascript';
    s.src='my_javascripts.js';
  }
  }
  window.onload=function(){loadCDN_or_local();};
  </script>

幾乎所有公共 CDN 都非常可靠。 但是,如果您擔心被阻止的 google 域,那么您可以簡單地回退到替代的jQuery CDN 但是,在這種情況下,您可能更願意采用相反的方式並使用其他一些 CDN 作為您的首選選項並回退到 Google CDN 以避免請求失敗和等待時間:

<script src="https://pagecdn.io/lib/jquery/3.2.1/jquery.min.js"></script>
<script>
   window.jQuery || document.write('<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"><\/script>');
</script>

盡管編寫document.write("<script></script>")對於 jQuery backoff 來說似乎更容易,但 Chrome 在這種情況下會給出驗證錯誤。 所以我更喜歡打破“腳本”這個詞。 所以它變得像上面一樣更安全。

<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.11.1.min.js"></script>
<script>if (typeof jQuery === "undefined") {
   window.jqFallback = true;
   document.write("<scr"+"ipt src='http://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.1/jquery.min.js'></scr"+"ipt>");
} </script>

對於長期問題,最好記錄 JQuery 回退。 在上面的代碼中,如果第一個 CDN 不可用,則從另一個 CDN 加載 JQuery。 但是您可能想知道錯誤的 CDN 並將其永久刪除。 (這種情況是非常特殊的情況)另外最好記錄回退問題。 所以你可以用 AJAX 發送錯誤的案例。 由於未定義 JQuery,您應該對 AJAX 請求使用 vanilla javascript。

<script type="text/javascript">
    if (typeof jQuery === 'undefined' || window.jqFallback == true) {
        // XMLHttpRequest for IE7+, Firefox, Chrome, Opera, Safari
        // ActiveXObject for IE6, IE5
        var xmlhttp = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
        var url = window.jqFallback == true ? "/yourUrl/" : "/yourUrl2/";
        xmlhttp.open("POST", url, true);
        xmlhttp.send();
    }
</script>

無法從您無法控制的外部數據存儲加載資源是很困難的。 尋找缺失的功能作為避免超時的一種手段是完全錯誤的,如本文所述: http : //www.tech-101.com/support/topic/4499-issues-using-a-cdn/

在 ASP.NET 中使用 Razor 語法,此代碼提供回退支持並使用虛擬根:

@{var jQueryPath = Url.Content("~/Scripts/jquery-1.7.1.min.js");}
<script type="text/javascript">
    if (typeof jQuery == 'undefined')
        document.write(unescape("%3Cscript src='@jQueryPath' type='text/javascript'%3E%3C/script%3E"));
</script>

或者做一個助手( 助手概述):

@helper CdnScript(string script, string cdnPath, string test) {
    @Html.Raw("<script src=\"http://ajax.aspnetcdn.com/" + cdnPath + "/" + script + "\" type=\"text/javascript\"></script>" +
        "<script type=\"text/javascript\">" + test + " || document.write(unescape(\"%3Cscript src='" + Url.Content("~/Scripts/" + script) + "' type='text/javascript'%3E%3C/script%3E\"));</script>")
}

並像這樣使用它:

@CdnScript("jquery-1.7.1.min.js", "ajax/jQuery", "window.jQuery")
@CdnScript("jquery.validate.min.js", "ajax/jquery.validate/1.9", "jQuery.fn.validate")

另一個備用替換ajax.googleapis.comcdnjs.cloudflare.com:

(function (doc, $)
{
    'use strict';

    if (typeof $ === 'undefined')
    {
        var script = doc.querySelector('script[src*="jquery.min.js"]'),
            src = script.src.replace('ajax.googleapis.com', 'cdnjs.cloudflare.com');

        script.parentNode.removeChild(script);
        doc.write('<script src="' + src + '"></script>');
    }
})(document, window.jQuery || window.Zepto);
  • 您可以通過在字符串中指定它來堅持使用 jQuery 版本
  • 非常適合不能使用 HTML 片段的資產管理
  • 在野外測試 - 非常適合來自中國的用戶

您可以使用以下代碼:

<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>window.jQuery || document.write('<script type="text/javascript" src="./scripts/jquery.min.js">\x3C/script>')</script>

但也有一些庫可用於為腳本設置幾種可能的回退並優化加載過程:

  • 籃子.js
  • 需要JS
  • 是的

例子:

bag.js我認為是目前最好的變體。 將您的腳本緩存在 localStorage 中,這將加快下一次加載。 最簡單的調用:

basket.require({ url: '/path/to/jquery.js' });

這將返回一個承諾,您可以在錯誤時進行下一次調用,或者在成功時加載依賴項:

basket
    .require({ url: '/path/to/jquery.js' })
    .then(function () {
        // Success
    }, function (error) {
        // There was an error fetching the script
        // Try to load jquery from the next cdn
    });

需要JS

requirejs.config({
    enforceDefine: true,
    paths: {
        jquery: [
            '//ajax.aspnetcdn.com/ajax/jquery/jquery-2.0.0.min',
            //If the CDN location fails, load from this location
            'js/jquery-2.0.0.min'
        ]
    }
});

//Later
require(['jquery'], function ($) {
});

是的

yepnope([{
  load: 'http://ajax.aspnetcdn.com/ajax/jquery/jquery-2.0.0.min.js',
  complete: function () {
    if (!window.jQuery) {
      yepnope('js/jquery-2.0.0.min.js');
    }
  }
}]);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM