Лучший способ использовать размещенный в Google jQuery, но отказываться от моей размещенной библиотеки в Google не удается
Как можно было бы попытаться загрузить размещенный jQuery в Google (или другие размещенные в Google библиотеки), но загрузить мою копию jQuery, если попытка Google не удалась?
Я не говорю, что Google ненадежен. В некоторых случаях копия Google блокируется (например, в Иране).
Я установил бы таймер и проверил бы для объекта jQuery?
Какова будет опасность того, что обе копии будут получены?
На самом деле не нужно искать ответы типа "просто воспользуйтесь Google" или "просто используйте свой". Я понимаю эти аргументы. Я также понимаю, что пользователь, скорее всего, будет кэшировать версию Google. Я имею в виду запасные варианты для облака в целом.
Редактировать: эта часть добавлена ...
Так как Google предлагает использовать google.load для загрузки библиотек ajax, и когда это сделано, он выполняет обратный вызов, мне интересно, является ли это ключом к сериализации этой проблемы.
Я знаю, это звучит немного безумно. Я просто пытаюсь понять, можно ли это сделать надежным способом или нет.
Обновление: jQuery теперь размещен на CDN от Microsoft.
24 ответа
Вы можете достичь этого следующим образом:
<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>
Как это работает, это использовать google
объект, который вызывает http://www.google.com/jsapi загружает на 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>');
}
Хотя, должен сказать, я не уверен, что, если это беспокоит посетителей вашего сайта, вам вообще стоит возиться с API библиотек Google AJAX.
Интересный факт: вначале я пытался использовать для этого блок 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();
}
}]);
Это загружает jQuery из Google-CDN. После этого проверяется, был ли jQuery успешно загружен. Если нет ("нет"), загружается локальная версия. Также загружаются ваши личные скрипты - "оба" указывает, что процесс загрузки инициируется независимо от результата теста.
Когда все процессы загрузки завершены, выполняется функция, в случае "MyApp.init".
Я лично предпочитаю этот способ асинхронной загрузки скрипта. И так как я полагаюсь на функциональные тесты, предоставляемые modernizr при создании сайта, я все равно встроил его в сайт. Так что на самом деле нет накладных расходов.
Здесь есть несколько отличных решений, но я хотел бы сделать еще один шаг в отношении локального файла.
В случае, если Google терпит неудачу, он должен загрузить локальный источник, но, возможно, физический файл на сервере не обязательно является лучшим вариантом. Я поднял этот вопрос, потому что в настоящее время я внедряю то же решение, только я хочу вернуться к локальному файлу, который генерируется источником данных.
Мои причины в том, что я хочу иметь некоторый разум, когда дело доходит до отслеживания того, что я загружаю из Google, и того, что у меня есть на локальном сервере. Если я хочу изменить версии, я хочу, чтобы моя локальная копия синхронизировалась с тем, что я пытаюсь загрузить из Google. В среде, где есть много разработчиков, я думаю, что лучшим подходом было бы автоматизировать этот процесс так, чтобы все, что нужно было сделать, это изменить номер версии в файле конфигурации.
Вот мое предлагаемое решение, которое должно работать в теории:
- В файле конфигурации приложения я буду хранить 3 вещи: абсолютный URL-адрес для библиотеки, URL-адрес для JavaScript API и номер версии
- Напишите класс, который получает содержимое файла самой библиотеки (получает 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);
}
После того, как вы попытаетесь включить копию Google из CDN.
В HTML5 вам не нужно устанавливать type
приписывать.
Вы также можете использовать...
window.jQuery || document.write('<script src="/libs/jquery.js"><\/script>');
Возможно, вы захотите использовать свой локальный файл в качестве последнего средства.
Похоже, что в настоящее время собственный CDN jQuery не поддерживает 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
переменная)
Как проверить неопределенную переменную в JavaScript
- Шаг 2. Динамический импорт (резервное копирование) файла javascript
Из-за проблемы запрета Google я предпочитаю использовать cdn от Microsoft http://www.asp.net/ajaxlibrary/cdn.ashx
Для тех, кто использует ASP.NET MVC 5, добавьте этот код в ваш BundleConfig.cs, чтобы включить CDN для 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);
Вот отличное объяснение этого!
Также реализует задержки загрузки и тайм-ауты!
http://happyworm.com/blog/2010/01/28/a-simple-and-robust-cdn-failover-for-jquery-14-in-one-line/
ОБНОВИТЬ:
Этот ответ оказался неверным. Пожалуйста, смотрите комментарии для реального объяснения.
Большинство из вас ответили на вопрос, но что касается заключительной части:
Какова будет опасность того, что обе копии будут получены?
Ни один на самом деле. Вы бы потратили пропускную способность, могли бы добавить несколько миллисекунд, загружая вторую бесполезную копию, но это не повредит, если они оба пройдут. Вы должны, конечно, избегать этого, используя методы, упомянутые выше.
if (typeof jQuery == 'undefined')) { ...
Или же
if(!window.jQuery){
Не будет работать, если версия cdn не загружена, потому что браузер будет проходить через это условие и во время него все еще загружает остальные javascripts, которым требуется jQuery, и он возвращает ошибку. Решением было загрузить сценарии через это условие.
<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>
Я считаю, что должен экранировать последний <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>
Почти все публичные 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>
Я сделал 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();
}
Google Hosted JQuery
- Если вы заботитесь о старых браузерах, в первую очередь о версиях IE до IE9, это наиболее широко совместимая версия 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
Невозможно загрузить ресурс из внешнего хранилища данных вне вашего контроля. Поиск недостающих функций совершенно ошибочен как средство избежать перерыва, как описано здесь: http://www.tech-101.com/support/topic/4499-issues-using-a-cdn/
Используя синтаксис Razor в ASP.NET, этот код обеспечивает резервную поддержку и работает с виртуальным корнем:
@{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")
Хотя пишу 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 недоступен, JQuery загружается из другого CDN. Но вы можете захотеть узнать этот ошибочный 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>
Еще один запасной вариант, который заменяет 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
- Протестировано в дикой природе - отлично работает для пользователей из Китая
Вы никогда не должны использовать личную копию. Вот мой полный сценарий пояса и подтяжек.
<!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>
Вы можете использовать код как:
<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
- yepnope
Примеры:
basket.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
});
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
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');
}
}
}]);