什么是尝试加载 the hosted jQuery at Google(或其他 Google 托管库)的好方法,但如果 Google 尝试失败则加载我的 jQuery 副本?
我并不是说谷歌是不稳定的。在某些情况下,谷歌副本被阻止(例如,显然在伊朗)。
我会设置一个计时器并检查 jQuery 对象吗?
两个副本都通过会有什么危险?
并不是真的在寻找“只使用谷歌”或“只使用你自己的”之类的答案。我理解这些论点。我也知道用户很可能缓存了 Google 版本。我正在考虑一般云的后备方案。
编辑:这部分添加...
由于 Google 建议使用 google.load 加载 ajax 库,并且在完成后执行回调,我想知道这是否是序列化此问题的关键。
我知道这听起来有点疯狂。我只是想弄清楚它是否可以以可靠的方式完成。
更新:jQuery 现在托管在 Microsoft 的 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/jsapi 加载到 window
对象的 google
对象。如果该对象不存在,我们假设对 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 Libraries 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”),则加载本地版本。您的个人脚本也会被加载——“both”表示加载过程是独立于测试结果启动的。
当所有加载过程完成后,将执行一个函数,例如“MyApp.init”。
我个人更喜欢这种异步脚本加载方式。由于我在构建站点时依赖于modernizr 提供的功能测试,因此无论如何我都将它嵌入到站点中。所以实际上没有开销。
这里有一些很棒的解决方案,但我想进一步了解本地文件。
在 Google 确实失败的情况下,它应该加载本地源,但服务器上的物理文件可能不一定是最佳选择。我提出这个是因为我目前正在实施相同的解决方案,只是我想退回到由数据源生成的本地文件。
我这样做的原因是,在跟踪我从 Google 加载的内容与本地服务器上的内容时,我想有一些想法。如果我想更改版本,我想让我的本地副本与我尝试从 Google 加载的内容保持同步。在一个有很多开发人员的环境中,我认为最好的方法是自动化这个过程,这样人们所要做的就是更改配置文件中的版本号。
这是我提出的理论上应该可行的解决方案:
在应用程序配置文件中,我将存储 3 件事:库的绝对 URL、JavaScript API 的 URL 和版本号
编写一个获取库本身文件内容的类(从应用配置获取 URL),将其存储在我的数据源中,并带有名称和版本号
编写一个处理程序,将我的本地文件从数据库中拉出并缓存文件,直到版本号更改。
如果它确实发生了变化(在我的应用程序配置中),我的类将根据版本号提取文件内容,将其作为新记录保存在我的数据源中,然后处理程序将启动并提供新版本。
理论上,如果我的代码编写正确,我需要做的就是更改我的应用程序配置中的版本号,然后中提琴!您有一个自动化的后备解决方案,您不必在服务器上维护物理文件。
大家怎么看?也许这是矫枉过正,但它可能是维护 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]-->
第 1 步:jQuery 是否加载失败? (检查 jQuery 变量)
How to check a not-defined variable in JavaScript
第 2 步:动态导入(备份)javascript 文件
How do I include a JavaScript file in another JavaScript file?
对于那些使用 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);
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js" integrity="sha256-VazP97ZCwtekAsvgPBSUwPFKdrwD3unUfSGVYrahUqU=" crossorigin="anonymous"></script>
,我们该怎么办?
更新:这个答案原来是错误的。真正的解释请看评论。
你们中的大多数问题都已得到解答,但至于最后一部分:
两个副本都通过会有什么危险?
真的没有。您会浪费带宽,下载第二个无用的副本可能会增加几毫秒的时间,但如果它们都通过,则不会造成实际伤害。当然,您应该使用上述技术避免这种情况。
我做了一个 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 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
我认为应该将字符串中的最后一个 < 转义为 \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>
if (typeof jQuery == 'undefined')) { ...
或者
if(!window.jQuery){
如果没有加载 cdn 版本,将无法正常工作,因为浏览器将在此条件下运行,并且在此期间仍会下载需要 jQuery 的其余 javascripts 并返回错误。解决方案是通过该条件加载脚本。
<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>
在 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 overview):
@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")
CdnScript
帮助程序,您每个脚本只需要一行代码。您拥有的脚本越多,收益就越大。
try { for (Script s : ...) cdnLoad(s); } catch (...) { for (Script s : ...) ownLoad(s); }
这样的东西。将其翻译成一堆 if
可能是一场噩梦。
尽管对于 jQuery 退避,编写 document.write("<script></script>")
似乎更容易,但 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,因此您应该使用 vanilla 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>
无法从您无法控制的外部数据存储中加载资源是很困难的。寻找丢失的函数作为避免超时的方法是完全错误的,如下所述:http://www.tech-101.com/support/topic/4499-issues-using-a-cdn/
另一个用 cdnjs.cloudflare.com 替换 ajax.googleapis.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
是的
例子:
篮子.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');
}
}
}]);
您永远不需要使用个人副本。这是我完整的腰带和大括号脚本。
<!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>
不定期副业成功案例分享