使用Google托管jQuery的最佳方法,但在Google上使用我的托管库失败


1016

尝试在Google(或其他Google托管库)中加载托管jQuery,但是如果Google尝试失败,则加载我的jQuery副本是什么好方法?

我并不是说Google很脆弱。在某些情况下,Google副本被阻止(例如,显然在伊朗)。

我会设置一个计时器并检查jQuery对象吗?

两份复印件通过的危险是什么?

并不是真正在寻找诸如“仅使用Google一个”或“仅使用您自己的”之类的答案。我理解那些论点。我也了解用户很可能已经缓存了Google版本。我通常在考虑云的回退。


编辑:这部分添加...

由于Google建议使用google.load加载ajax库,并且完成后会执行回调,所以我想知道这是否是序列化此问题的关键。

我知道这听起来有点疯狂。我只是想弄清楚它是否可以可靠地完成。


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

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


9
当然,第一个答案是“不要使用Google托管版本”。:-)
Nosredna

7
当然,这是因为如果您想托管一个严肃的网站,则无需依赖其他人托管您的文件。
Bryan Migliorisi

6
@Bryan Migliorisi,我想Twitter毕竟不是那么认真吗?但我承认,就像一个月前Google倒闭一样,他们在Google方面遇到了问题。
Ionuț G. Stan,2009年

18
对于不使用Google进行JS lib托管的优点是值得的,但在其他几个线程中也对此进行了讨论。我一直在寻找有关JS载入延迟方面的技术解答。
Nosredna

2
@Joe Chung:它很可能缓存在用户的系统上,从而加快了页面加载速度。节省我带宽。使用Google的CDN。等等
Nosredna 2009年

Answers:


810

您可以这样实现:

<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 ready事件处理程序都应该在其中<body>以避免发生错误(尽管它不是万无一失的!)。

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


35
javascript下载是否已经阻止(同步)了?因此,在我看来,双重复制问题不是问题。
马特·谢尔曼

68
正如Matt Sherman所说,JavaScript下载应该已经是同步的。否则,如果页面尝试执行仅下载了一半的库所依赖的内联脚本,或者在未完全下载并执行该库的情况下执行了库扩展,则会出现许多问题。这也是Yahoo YSlow建议将javascript放在页面末尾的原因之一;因此它不会阻止其他页面元素(包括样式和图像)的下载。至少,浏览器必须延迟执行顺序才能执行。
gapple

42
验证者的一个小修正:字符串'</'在JavaScript中是不允许的,因为它可能被误解为script标签(SGML短标签表示法)的结尾。改用'<'+'/ script>'。干杯,
Boldewyn

8
此示例将不起作用。1)如果Google ajax库不可用,则必须先超时才能失败。可能还要等一下。在我断开计算机与网络的连接的测试中,它只是尝试并且尝试并且尝试并且没有超时。2)如果(!jQuery)将抛出错误,因为未定义jQuery,因此Javascript不知道如何处理它。
RedWolves

32
要测试是否已加载jQuery,(!window.jQuery)可以正常工作,然后将其短接typeof检查。
约恩·泽弗勒(JörnZaefferer)2009年

335

到目前为止,最简单,最干净的方法是:

<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>

1
@jpp不是为了XHTML 1.0HTML 4.01
BenjaminRH

5
人们不断要求我删除这些type="text/javascript"部分,因此对于为较旧的浏览器编写html的人们,请注意,您现在必须添加这些内容
BenjaminRH

6
@BenjaminRH:type="text/javascript"在旧的浏览器中也不需要,因为它们都默认为Javascript。确实是较老的浏览器着眼于该language属性。但即使如此,如果缺少该属性,则Javascript是默认设置。
马丁·

1
@Martijn但我喜欢闪亮的验证徽章:)
BenjaminRH

3
@Trojan完全有可能,只需堆叠调用即可。请注意,此时您要打开新的连接主机,因此HTTP管道传输可能会更快。... <script src="//cdn1.com/jquery.js"></script> <script>window.jQuery || document.write('<script src="//cdn2.com/jquery.js"><\/script>')</script> <script>window.jQuery || document.write('<script src="local/jquery.js"><\/script>')</script>
Tom McKenzie 2014年

76

这似乎为我工作:

<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>

它的工作方式是使用google调用http://www.google.com/jsapiwindow对象加载到该对象上。如果该对象不存在,则我们假设对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块,但找不到如此干净的组合。我很想看看这个想法的其他实现,纯粹是作为练习。


1
在这种情况下使用google.load而不是像Rony建议的那样直接加载ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js有什么好处?我猜加载它也直接捕获了删除的库的问题(如果Google停止提供JQuery 1.3.2的话)。此外,在提取了www.google.com/jsapi之后,Rony的版本会注意到网络问题,尤其是当从缓存中加载jsapi时?可能需要使用google.load回调函数来确定(或者可能有一些返回值将google.load包含在if(..)中)。
Arjan

如果要测试是否存在Google.com,则可以拨打网络电话,也可以检查是否存在“关守”对象。我正在做的是检查google对象及其“加载”功能。如果两者均失败,则没有google,我需要本地版本。Rony的版本实际上完全忽略了www.google.com/jsapi URL,所以我不确定为什么您指出它将被获取。
artlung

最后,所需要做的就是加载jquery库。不需要任何Google库。用Rony的答案,可以肯定地知道从Google(或缓存)加载是否成功。但是在检查“ if(window.google && window.google.load)”时,仍未加载jquery库。jQuery库的实际加载未经过验证?
Arjan

嗯,我明白我是怎么造成混乱的。“ Rony的版本在获取www.google.com/jsapi之后会注意到网络问题”应该更好地读为:“您的版本在www.google.com/jsapi被获取后不会注意到网络问题”。
Arjan

2
我们最近已改用Google作为jQuery主机;如果我们从被阻止的用户那里收到任何错误报告,我将使用您的答案的一种变体来重构我们的客户端代码。好答案!
Jarrod Dixon

30

如果您的网站上嵌入了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。否则(“否”),将加载本地版本。同样,您的个人脚本也已加载-“两者”都表示加载过程独立于测试结果启动。

完成所有加载过程后,在“ MyApp.init”的情况下,将执行一个函数。

我个人更喜欢这种异步脚本加载方式。而且,由于我在构建站点时依赖modernizr提供的功能测试,因此无论如何我都将其嵌入在站点中。因此,实际上没有开销。


2
我认为您遗漏了问题的要点-如何从CDN加载moernizr脚本?
George Filippakos

2
我不建议从CDN加载Modernizr。宁可从modernizr.com获得最小的自定义版本。
伊曼纽尔·克鲁格

2
因此,与其他选项获得的500/200 +相比,该选项获得+16。但这听起来不错。依靠Modernizer只是不受欢迎吗?无论如何,我还是在我们的网站上使用了Modernizer,因此,如果这比其他答案要好,有人可以让我知道吗?我对JQuery还是很陌生,因此请您澄清一下。
redfox05 2014年

2
在回答时,这确实是一个不错的选择,但自2015年起yepnope.js已弃用。看到stackoverflow.com/questions/33986561/...
Obmerk皇冠

Modernizr的创建就是为了解决此类问题。+1
Carlos Quijano

21

这里有一些很棒的解决方案,但是我想对本地文件更进一步。

在Google确实失败的情况下,它应该加载本地源,但是服务器上的物理文件不一定是最佳选择。之所以提出这一点,是因为我当前正在实现相同的解决方案,只是我想回退到由数据源生成的本地文件。

我这样做的原因是,在跟踪从Google加载的内容与在本地服务器上获取的内容时,我想有所了解。如果要更改版本,我希望将本地副本与我尝试从Google加载的内容保持同步。在有许多开发人员的环境中,我认为最好的方法是使这一过程自动化,以便所有人要做的就是更改配置文件中的版本号。

这是我建议的在理论上可行的解决方案:

  • 在应用程序配置文件中,我将存储3件事:库的绝对URL,JavaScript API的URL和版本号
  • 写一个类,获取库本身的文件内容(从应用程序配置中获取URL),并将其与名称和版本号一起存储在我的数据源中
  • 编写一个处理程序,将我的本地文件从数据库中拉出并缓存该文件,直到版本号更改为止。
  • 如果确实发生更改(在我的应用程序配置中),则我的类将根据版本号提取文件内容,将其另存为我的数据源中的新记录,然后处理程序将启动并提供新版本。

从理论上讲,如果我的代码编写正确,那么我要做的就是更改应用程序配置中的版本号,然后更改中提琴!您有一个自动化的后备解决方案,无需维护服务器上的物理文件。

大家怎么想 也许这是矫kill过正,但它可能是维护AJAX库的一种优雅方法。

橡子


如果您只是为jQuery完成所有工作,那么我会说这过分了。但是,如果您已经为应用程序的其他部分准备了一些组件(例如,如果您已经从数据库中加载脚本),那么它看起来就不错了。
Michael Haren 2010年

1
+1透彻新颖,尽管我不相信这样做的好处可以证明开发时间和复杂性。
科里之家

20
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>');

2
+1看起来更干净。顶部有一个小错别字,我无法清除,因为在“ undefined”之后,它的两个小括号非常明显
naveen

1
第一种选择避免了Chrome的警告[Violation] Avoid using document.write().
鲍勃·斯坦因

不幸的是,第一个选项似乎没有同步加载。第二个选择
鲍勃·斯坦

10

您可能希望将本地文件用作最后的选择。

到目前为止,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> 

真的需要多个后备吗?如果两者都离线,则用户将等待一分钟以上才能看到您的网站
George Filippakos 2013年

1
脚本加载不需要一分钟,而是完成了。
爱德华·奥拉米桑

@ geo1701和爱德华,真的不需要三分之一。甚至还没有一个退路被证明是可靠的。如果Google API出现故障,我还无法保证首次尝试将完全失败。我经历过的情况,其中一个CDN再也没能负荷,从不断渲染持有的页面,这里提到:stevesouders.com/blog/2013/03/18/http-archive-jquery/...
hexalys

6

有条件地加载最新/旧版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]-->

这不是跨浏览器兼容的。
Josh Habdas

乔希,是的。
neiker



4

这是一个很好的解释!

还实现了加载延迟和超时!

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


仅链接的答案无用,被认为是低质量的。考虑将相关的位复制到您的答案中,当然要注明出处。
random_user_name

@cale_b你在开玩笑吗?该答案已有7年以上的历史,因此此注释是不必要的。
Stuart.Sklinar,

是的,这是个老答案。尽管他们的建议是有效的。答案只是其他地方的链接,可以删除。进一步的读者:meta.stackoverflow.com/q/8259
罗布

我完全同意,我本人会提出一些建议,但7年后再说也没有意义。它应该像7年前那样而不是7年前那样进行审核。
Stuart.Sklinar,

1
@ Stuart.Sklinar-如果我7年前看过它,我会:)我发现自己在这里做了一些研究,并且是第一次看到它。抱歉让您感到沮丧-我认为我们在SO上的工作将成为该网站的管理员,这有时意味着评论,编辑或改善旧的问题或答案...
random_user_name

4

对于那些使用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);

4

更新:
这个答案原来是错误的。请查看评论以获取真正的解释。


你们大多数人的问题已经回答,但至于最后一部分:

两份复印件通过的危险是什么?

真的没有。您会浪费带宽,可能会花上几毫秒的时间来下载第二个无用的副本,但是如果它们都通过了,那并没有实际的危害。当然,您应该使用上述技术避免这种情况。


5
实际上,根据问题,两次加载jQuery可能会导致很多问题
ShadowCat13年

为什么不自己进行测试并手动加载两次jQuery库。然后答案就会显示出来。
luke_mclachlan 2015年

到底为什么这么错?@ ShadowCat7您能否更详细地说明它引起的问题?我看到您链接的问题中明确指出的唯一问题是“清除所有以前加载的插件”。但这不应该适用于两次连续地加载相同的jQuery文件,对吗?我之所以问是因为这里针对本地后备的其他解决方案太复杂了,而document.write 在某些地方被认为是邪恶的
鲍勃·斯坦

2

我制作了一个Gist,如果尚未加载jQuery,则应动态加载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();
}

2

Google托管的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


注意通过不安全的协议加载脚本会打开XSS攻击媒介。
乔什·哈布达斯

2

我认为应该转义最后一个<到\ 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>

2
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>

我在测试Google Chrome浏览器中的脚本时发现了一个问题-缓存。因此,对于本地测试,只需将else部分中的src替换为s.src ='my_javascripts.js'+'?'+ Math.floor(Math.random()* 10001);
MirekKomárek,

如果未加载cdn版本,Alex的答案将不起作用,因为浏览器将在这种情况下运行,并且在此过程中仍在下载需要jquery的其余javascript,并返回错误 ->正在下载的JavaScript文件将阻止运行下一段代码所以这不是问题
alex

2

几乎所有公共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>

1

此代码在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")

我从来心脏约剃须刀,但它看起来像一个混淆,不同的是它使代码长,而不是更短(只要它的两倍,这个
maaartinus

@maaartinus:这不是一个苹果对苹果的比较。您所引用的BenjaminRH的答案是针对单个CDN托管的脚本的。使用CdnScript帮助程序,每个脚本只需要一行代码。您拥有的脚本越多,收益就越大。
爱德华·布雷

当然...那只是a。但是,我认为这不是最佳方法。如果失败,我将完全忽略CDN并切换到所有脚本的后备。我不确定这是否可行,因为我不知道加载的工作原理。
maaartinus

@maaartinus:由于每个CDN脚本加载都可以独立失败,因此您必须分别检查每个加载。没有可靠的方法来进行单个CDN检查,然后再从CDN加载所有脚本。
爱德华·布雷

使我担心的情况是CDN站点的故障导致许多负载的等待时间。所以我想吃点东西try { for (Script s : ...) cdnLoad(s); } catch (...) { for (Script s : ...) ownLoad(s); }。将其转换为一堆ifs可能是一场噩梦。
maaartinus 2014年

1

尽管document.write("<script></script>")对于jQuery后退而言,编写似乎更容易,但是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,因此应使用香草javascript进行AJAX请求。

<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>


0

另一个后备版本,将ajax.googleapis.com替换为cdnjs.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片段的资产管理
  • 经过野外测试-非常适合来自中国的用户

您能否详细说明以下语句:“您不必关心jQuery版本”?
Josh Habdas

该版本是该方法无法使用的URL的一部分... jquery / 3.xx / jquery.min.js
redaxmedia

1
当jQuery修订到版本4并引入向后不兼容的更改时,是否有可能导致损坏?
Josh Habdas

-1,因为如果jQuery引入了除非您指定了版本的脚本,否则您的脚本尚不支持的重大更改将导致损坏。
Lookaji

@lookaji我认为您不了解后备功能。它确实替换了托管它的域,并且完全不修改文件名/版本。
redaxmedia

0

您可以使用如下代码:

<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>

但是,还有一些库可用于为脚本设置多个可能的后备版本并优化加载过程:

  • basket.js
  • RequireJS
  • 耶普诺普

例子:

basket.js 我认为目前是最好的变体。将您的脚本缓存在localStorage中,这将加快下一次加载的速度。最简单的调用:

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

这将返回一个Promise,您可以对错误进行下一个调用,或者在成功时加载依赖项:

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
    });

RequireJS

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');
    }
  }
}]);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.