使用Google托管jQuery的最佳方式,但在Google上回退到我的托管库失败

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

我不是说谷歌是不可靠的。在某些情况下,谷歌的副本被封锁了(例如,显然在伊朗)。

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

两个副本都通过的危险是什么?

不是真的在寻找“只用谷歌的”或“只用你自己的”之类的答案。我理解这些论点。我也明白用户很可能缓存了谷歌版本。我正在考虑一般的云计算回退。


编辑:这部分添加了…

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

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


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

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

165088 次浏览

你可以像这样实现它:

<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的域名被禁止。

这似乎为我工作:

<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/jsapi加载到window对象上的google对象。如果该对象不存在,我们假设访问Google失败。如果是这种情况,我们使用document.write加载本地副本。(在这种情况下,我使用自己的服务器,请使用您自己的服务器进行测试)。

我还测试window.google.load的存在-我也可以做一个typeof检查,看看东西是对象还是函数。但我认为这确实有技巧。

这只是加载逻辑,因为代码突出显示似乎失败,因为我发布了我正在测试的整个超文本标记语言页面:

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

虽然我必须说,我不确定,如果这是一个关注你的网站访问者,你应该摆弄谷歌AJAX库API

有趣的事实我最初尝试在各种版本中为此使用try… cat块,但找不到像这样干净的组合。我有兴趣看到这个想法的其他实现,纯粹作为练习。

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

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

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

这是我提出的理论上应该可行的解决方案:

  • 在应用程序配置文件中,我将存储3件东西:库的绝对URL、JavaScript API的URL和版本号
  • 编写一个类,获取库本身的文件内容(从app config获取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>');
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 scriptsvar 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 scriptsvar 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的封禁问题,我更喜欢使用微软的cdnhttp://www.asp.net/ajaxlibrary/cdn.ashx

  • 第1步:jQuery加载失败了吗?(检查jQuery变量)

如何在JavaScript中检查未定义的变量

  • 第2步:动态导入(备份)javascript文件

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

在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")

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

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

如果您的站点上嵌入了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”的情况下。

我个人更喜欢这种异步脚本加载的方式。由于我在构建网站时依赖现代化提供的功能测试,因此我将其嵌入在网站上。所以实际上没有开销。

更新:
这个答案被证明是错误的。请看评论中的真实解释。


大多数问题已经回答了,但至于最后一部分:

两个副本都通过的危险是什么?

没有。你会浪费带宽,可能会增加一些毫秒下载第二个无用的副本,但如果它们都通过,则没有实际伤害。当然,您应该使用上述技术避免这种情况。

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

似乎现在jQuery自己的CDN不支持https。如果是这样,你可能想先从那里加载。

所以这是序列:谷歌CDN=>微软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>

我认为应该转义字符串中的最后一个

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

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

我做了一个Gist,如果它还没有加载,它应该动态加载jQuery,如果源失败,它会继续回退(从许多答案拼接在一起):https://gist.github.com/tigerhawkvok/9673154

请注意,我计划保持要点更新,但不是这个答案,为了它的价值!

/* See https://gist.github.com/tigerhawkvok/9673154 for the latest version */function cascadeJQLoad(i) { // Use alternate CDNs where appropriate to load jQueryif (typeof(i) != "number") i = 0;// the actual paths to your jQuery CDNsvar 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 jQueryvar 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 alreadyif (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 jQueryif (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 browserswindow.onreadystatechange = function() {if (this.readyState == 'complete' || this.readyState == 'loaded') {cascadeJQLoad();}}} else { //modern browserscascadeJQLoad();}

对于那些使用ASP.NETMVC 5的人,请在BundleConfig.cs中添加此代码以启用CDN for jQuery:

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

虽然编写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, IE5var 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/

另一个回退将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版本
  • 非常适合不适用于超文本标记语言片段的资产管理
  • 在野外测试-非常适合来自中国的用户

谷歌托管jQuery

  • 如果您关心较旧的浏览器,主要是IE9之前的IE版本,这是最广泛兼容的jQuery版本
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
  • If you don’t care about oldIE, this one is smaller and faster:
<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

您可以使用以下代码:

<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
  • 是否必填
  • yepnope

示例:

<强>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.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']}});
//Laterrequire(['jquery'], function ($) {});

yepnope

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

几乎所有的公共CDN都是相当可靠的。但是,如果您担心谷歌域被阻止,那么您可以简单地回退到替代方案jQuery CDN然而在这种情况下你可能宁愿做相反的方式并使用其他一些CDN作为您的首选选项,并回退到谷歌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>

你永远不需要使用个人副本。这是我完整的腰带和括号脚本。

<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"/><title>jQuery</title><!-- EMBED JQUERY USING GOOGLE APIs --><script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<!-- IF THAT FAILS EMBED JQUERY USING CLOUDFLARE CDN --><script type="text/javascript">window.jQuery || document.write('<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"><\/script>');</script>
<!-- IF THAT FAILS ************* HOW??? *********** EMBED JQUERY FROM MICROSOFT --><script type="text/javascript">window.jQuery || document.write('<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.6.0.min.js"><\/script>');</script>
<!-- IF THAT FAILS ************* WOW!!! *********** EMBED JQUERY FROM JQUERY.COM --><script type="text/javascript">window.jQuery || document.write('<script src="https://code.jquery.com/jquery-3.6.0.min.js"><\/script>');</script>
<!-- IF THAT FAILS ************* LET'S STOP!!! *********** EMBED JQUERY FROM PERSONAL COPY --><script type="text/javascript">window.jQuery || document.write('<script src="jquery.min.js"><\/script>');</script></head><body>

</body></html>