Najlepszy sposób na skorzystanie z hostowanej przez Google jQuery, ale wróć do mojej hostowanej biblioteki Google


1016

Jaki byłby dobry sposób próby załadowania hostowanego jQuery w Google (lub innych bibliotekach hostowanych przez Google), ale załadowania mojej kopii jQuery, jeśli próba Google się nie powiedzie?

Nie twierdzę, że Google jest niestabilny. Są przypadki, w których kopia Google jest zablokowana (na przykład w Iranie).

Czy ustawiłbym licznik czasu i sprawdzał obiekt jQuery?

Jakie byłoby niebezpieczeństwo, że obie kopie przejdą?

Naprawdę nie szukam odpowiedzi typu „po prostu użyj Google” lub „po prostu użyj własnego”. Rozumiem te argumenty. Rozumiem również, że użytkownik prawdopodobnie buforuje wersję Google. Myślę ogólnie o awariach w chmurze.


Edycja: Dodano tę część ...

Ponieważ Google sugeruje użycie google.load do załadowania bibliotek ajax, a po zakończeniu wykonuje wywołanie zwrotne, zastanawiam się, czy to jest klucz do serializacji tego problemu.

Wiem, że to trochę szalone. Próbuję tylko dowiedzieć się, czy można to zrobić w wiarygodny sposób, czy nie.


Aktualizacja: jQuery jest teraz hostowany na CDN Microsoftu.

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


9
Oczywiście pierwszą odpowiedzią było „nie używaj wersji hostowanej w Google”. :-)
Nosredna

7
Oczywiście dlatego, że jeśli chcesz hostować poważną stronę internetową, nie polegasz na kimś innym, kto hostuje twoje pliki.
Bryan Migliorisi

6
@Bryan Migliorisi, myślę, że Twitter wcale nie jest taki poważny? Ale przyznaję, że mieli problemy z Google, jak miesiąc temu, kiedy Google przestał działać.
Ionuț G. Stan

18
Korzyści z używania Google lub nie dla JS lib hosting są godne, ale zostało to omówione w kilku innych wątkach. Szukałem technicznych odpowiedzi dotyczących powrotu JS do opóźnień w ładowaniu.
Nosredna

2
@Joe Chung: Prawdopodobnie będzie buforowany w systemie użytkownika, co przyspieszy ładowanie strony. Oszczędza mi przepustowość. Wykorzystuje CDN Google. Itd.
Nosredna

Odpowiedzi:


810

Możesz to osiągnąć w następujący sposób:

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

Powinno to znajdować się na twojej stronie, <head>a wszelkie procedury obsługi zdarzeń gotowe do jQuery powinny być w <body>celu uniknięcia błędów (chociaż nie jest to głupie!).

Kolejnym powodem, dla którego nie należy używać jQuery obsługiwanego przez Google, jest to, że w niektórych krajach nazwa domeny Google jest zbanowana.


35
Czy pobieranie javascript nie jest już blokowane (synchroniczne)? Wydaje mi się, że kwestia podwójnego kopiowania nie byłaby zatem problemem.
Matt Sherman,

68
Pobieranie Javascript powinno być już zsynchronizowane, jak powiedział Matt Sherman. W przeciwnym razie wystąpiłoby wiele problemów, gdyby strona próbowała wykonać skrypt wbudowany, który opierał się na bibliotece, która została pobrana tylko w połowie lub rozszerzenie biblioteki zostało wykonane bez biblioteki w całości pobranej i wykonanej. To także jeden z powodów, dla których Yahoo YSlow zaleca umieszczanie javascript na końcu stron; aby nie blokował pobierania innych elementów strony (w tym stylów i obrazów). Przeglądarka musiałaby przynajmniej opóźnić wykonanie, aby nastąpiło sekwencyjnie.
gapple

42
Mała poprawka od fanatyka walidatora: Łańcuch „</” jest niedozwolony w JavaScript, ponieważ może być źle interpretowany jako koniec znacznika skryptu (notacja krótkiego znacznika SGML). Zamiast tego należy wykonać polecenie <<+ + / script>. Pozdrawiam,
Boldewyn

8
Ten przykład nie zadziała. 1) jeśli biblioteka Google ajax nie jest dostępna, musi upłynąć limit czasu, zanim zakończy się niepowodzeniem. To może zająć chwilę. W moim teście odłączenia komputera od sieci po prostu próbowałem, próbowałem i próbowałem, i nie przekroczyłem limitu czasu. 2) if (! JQuery) zgłosi błąd, ponieważ jQuery nie jest zdefiniowany, więc Javascript nie wie, co z tym zrobić.
RedWolves

32
Aby sprawdzić, czy jQuery został załadowany, (! Window.jQuery) działa dobrze i jest zwarty, a następnie sprawdzanie typu.
Jörn Zaefferer

335

Jak dotąd najłatwiejszy i najczystszy sposób:

<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 nie dla XHTML 1.0iHTML 4.01
BenjaminRH

5
Ludzie wciąż proszą mnie o usunięcie type="text/javascript"części, więc osobom piszącym HTML dla starszych przeglądarek pamiętaj, że teraz musisz to dodać.
BenjaminRH

6
@BenjaminRH: nie type="text/javascript"było również konieczne w starszych przeglądarkach, ponieważ wszystkie domyślnie używały Javascript. Naprawdę starsze przeglądarki przeglądały ten languageatrybut; ale nawet wtedy JavaScript był domyślny, jeśli brakowało atrybutu.
Martijn

1
@Martijn Ale podobała mi się błyszcząca plakietka weryfikacji :)
BenjaminRH

3
@Trojan Całkowicie możliwe, po prostu stos połączeń. Pamiętaj, że w tym momencie otwierasz nowe hosty połączeń, więc potokowanie HTTP prawdopodobnie będzie szybsze. ... <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

76

Wydaje mi się, że to działa:

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

Działa to w ten sposób, że używa googleobiektu, który wywołuje http://www.google.com/jsapi ładowany do windowobiektu. Jeśli ten obiekt nie jest obecny, zakładamy, że dostęp do Google nie działa. W takim przypadku ładujemy lokalną kopię za pomocą document.write. (W tym przypadku korzystam z własnego serwera, proszę użyć własnego do przetestowania tego).

Testuję również obecność window.google.load- Mógłbym również typeofsprawdzić, czy rzeczy są odpowiednio obiektami lub funkcjami. Ale myślę, że to wystarczy.

Oto logika ładowania, ponieważ podświetlenie kodu wydaje się nie działać, ponieważ opublikowałem całą stronę HTML, którą testowałem:

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

Chociaż muszę powiedzieć, nie jestem pewien, że jeśli jest to problem dla odwiedzających twoją witrynę, powinieneś w ogóle bawić się interfejsem API bibliotek Google AJAX .

Ciekawostka : na początku próbowałem użyć do tego bloku try..catch w różnych wersjach, ale nie mogłem znaleźć tak czystej kombinacji. Chciałbym zobaczyć inne implementacje tego pomysłu, wyłącznie jako ćwiczenie.


1
Jaka jest zaleta korzystania z google.load w tej sytuacji, zamiast bezpośredniego ładowania ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js, jak sugerował Rony? Myślę, że załadowanie go bezpośrednio wychwytuje również problemy z usuniętymi bibliotekami (co jeśli Google przestanie obsługiwać JQuery 1.3.2). Co więcej, wersja Rony zauważa problemy z siecią PO PO pobraniu www.google.com/jsapi, szczególnie gdy jsapi został załadowany z pamięci podręcznej? Być może trzeba będzie użyć wywołania zwrotnego google.load, aby się upewnić (a może istnieje pewna wartość zwracana, aby dołączyć google.load do if (..)).
Arjan

Jeśli ktoś testuje obecność Google.com, może wykonać połączenie sieciowe lub sprawdzić obecność obiektu „strażnika”. To, co robię, to sprawdzanie obiektu Google i jego funkcji „ładowania”. Jeśli oba zawiodą, nie ma google i potrzebuję wersji lokalnej. Wersja Rony'ego całkowicie ignoruje adres URL www.google.com/jsapi, więc nie jestem pewien, dlaczego podajesz, że został pobrany.
artlung

Ostatecznie wszystko, co jest wymagane, to załadowanie biblioteki jquery. Żadna biblioteka Google nie jest wymagana. W odpowiedzi Rony'ego wiadomo na pewno, czy ładowanie z Google (lub pamięci podręcznej) się powiodło. Ale przy sprawdzaniu „if (window.google && window.google.load)” biblioteka jquery nadal nie jest ładowana. Rzeczywiste ładowanie biblioteki jquery nie jest sprawdzone?
Arjan

ah, widzę, jak spowodowałem zamieszanie. „Wersja Rony zauważa problemy z siecią PO pobraniu strony www.google.com/jsapi” powinna przeczytać: „Twoja wersja nie zauważa problemów z siecią PO pobraniu strony www.google.com/jsapi”.
Arjan

2
Niedawno przeszliśmy na używanie Google jako naszego hosta jQuery; jeśli otrzymamy jakiekolwiek raporty o błędach od zablokowanych użytkowników, użyję wariantu twojej odpowiedzi, aby refaktoryzować nasz kod klienta. Dobra odpowiedź!
Jarrod Dixon

30

Jeśli masz w witrynie modernizr.js, możesz użyć wbudowanego yepnope.js do asynchronicznego ładowania skryptów - między innymi jQuery (z rezerwą).

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

To ładuje jQuery z Google-cdn. Następnie jest sprawdzane, czy jQuery zostało pomyślnie załadowane. Jeśli nie („nie”), ładowana jest wersja lokalna. Załadowane są również twoje osobiste skrypty - „oba” oznaczają, że proces ładowania jest inicjowany niezależnie od wyniku testu.

Po zakończeniu wszystkich procesów ładowania wykonywana jest funkcja, w przypadku „MyApp.init”.

Osobiście wolę ten sposób asynchronicznego ładowania skryptów. I ponieważ polegam na testach funkcji dostarczonych przez moderatora podczas tworzenia strony, i tak mam to osadzone na stronie. Więc tak naprawdę nie ma narzutów.


2
Myślę, że nie rozumiesz sedna pytania - jak zabrałbyś się do ładowania skryptu moernizr z CDN?
George Filippakos

2
Nie mogę polecić ładowania Modernizr z CDN. Należy raczej uzyskać najmniejszą niestandardową wersję z modernizr.com.
Emanuel Kluge

2
Tak więc ta opcja dostaje +16, w porównaniu do 500/200 +, które otrzymują inne opcje. Ale to brzmi całkiem dobrze. Czy to po prostu nie jest popularne z powodu polegania na Modernizer? W każdym razie zdarza mi się używać Modernizera na naszej stronie, więc jeśli jest to lepsze niż inne odpowiedzi, czy ktoś może dać mi znać? Jestem całkiem nowy w JQuery, więc wyjaśnienie jest mile widziane.
redfox05,

2
To była naprawdę dobra opcja w czasie odpowiedzi, ale od 2015 roku yepnope.jsjest przestarzała. patrz stackoverflow.com/questions/33986561/…
Obmerk Kronen

Modernizr został stworzony do rozwiązywania problemów takich jak to pytanie. +1
Carlos Quijano

21

Jest tu kilka świetnych rozwiązań, ale chciałbym pójść o krok dalej w kwestii pliku lokalnego.

W scenariuszu, gdy Google zawiedzie, powinien załadować lokalne źródło, ale może fizyczny plik na serwerze niekoniecznie jest najlepszą opcją. Mówię o tym, ponieważ obecnie wdrażam to samo rozwiązanie, tylko chcę wrócić do lokalnego pliku, który jest generowany przez źródło danych.

Moim powodem jest to, że chcę mieć trochę spokoju, jeśli chodzi o śledzenie tego, co ładuję z Google, a co mam na lokalnym serwerze. Jeśli chcę zmienić wersje, chcę zsynchronizować moją kopię lokalną z tym, co próbuję załadować z Google. Myślę, że w środowisku, w którym jest wielu programistów, najlepszym rozwiązaniem byłoby zautomatyzowanie tego procesu, tak aby wystarczyło tylko zmienić numer wersji w pliku konfiguracyjnym.

Oto moje proponowane rozwiązanie, które powinno działać w teorii:

  • W pliku konfiguracji aplikacji zapiszę 3 rzeczy: bezwzględny adres URL biblioteki, adres URL interfejsu API JavaScript i numer wersji
  • Napisz klasę, która pobierze zawartość pliku samej biblioteki (pobierze adres URL z konfiguracji aplikacji), zapisze go w moim źródle danych z nazwą i numerem wersji
  • Napisz moduł obsługi, który wyciągnie mój plik lokalny z bazy danych i buforuje plik do momentu zmiany numeru wersji.
  • Jeśli to się zmieni (w mojej konfiguracji aplikacji), moja klasa pobierze zawartość pliku na podstawie numeru wersji, zapisze go jako nowy rekord w moim źródle danych, a następnie program obsługi uruchomi nową wersję.

Teoretycznie, jeśli mój kod jest napisany poprawnie, wszystko, co musiałbym zrobić, to zmienić numer wersji w konfiguracji aplikacji, a następnie viola! Masz zautomatyzowane rozwiązanie awaryjne i nie musisz utrzymywać fizycznych plików na serwerze.

Co wszyscy myślą? Może to przesada, ale może to być elegancka metoda zarządzania bibliotekami AJAX.

Żołądź


Jeśli wykonujesz całą tę pracę tylko dla jQuery, powiedziałbym, że to przesada. Jeśli jednak masz już niektóre z tych komponentów dla innych elementów aplikacji (np. Jeśli już ładujesz skrypty z bazy danych), to wygląda całkiem nieźle.
Michael Haren,

1
+1 za dokładność i powieść, choć nie jestem przekonany, że korzyść uzasadnia czas i złożoność twórców.
Cory House,

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

}

Po próbie dołączenia kopii Google z CDN.

W HTML5 nie musisz ustawiać typeatrybutu.

Możesz także użyć...

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

2
+1 wygląda na czystsze. na górze jest drobna literówka, której nie mogę wyczyścić, ponieważ jej dwa drobne nawiasy zamykające po „niezdefiniowanym”
naveen

1
Pierwsza opcja pozwala uniknąć ostrzeżenia Chrome[Violation] Avoid using document.write().
Bob Stein

Pierwsza opcja niestety nie wydaje się ładować synchronicznie . Tak robi druga opcja .
Bob Stein

10

Możesz użyć lokalnego pliku jako ostateczności.

Wydaje się, że obecnie własny CDN jQuery nie obsługuje https. Jeśli tak, możesz najpierw załadować stamtąd.

Oto sekwencja: Google CDN => Microsoft CDN => Twoja lokalna kopia.

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

Czy naprawdę istnieje potrzeba więcej niż jednego powrotu? jeśli oboje są offline, użytkownik będzie czekał ponad minutę, zanim zobaczy twoją stronę
George Filippakos

1
Załadowanie skryptu nie zajmuje 1 minuty, prawda?
Edward Olamisan

@ geo1701 i Edward, Tak naprawdę nie ma potrzeby trzeciej. Nawet jedna awaria nie została jeszcze udowodniona jako niezawodna. Jeśli interfejs API Google jest wyłączony, nie widziałem żadnych gwarancji, że pierwsza próba w ogóle się nie powiedzie. Doświadczyłem scenariusz przypadku gdy CDN nigdy nie udało się załadować, trzymając stronę z historii trójwymiarowa, jak wspomniano tutaj: stevesouders.com/blog/2013/03/18/http-archive-jquery/...
hexalys

6

Warunkowo załaduj najnowszą / starszą wersję jQuery i powrót do poprzedniej wersji:

<!--[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]-->

To nie jest kompatybilne z wieloma przeglądarkami.
Josh Habdas,

Josh, tak, to prawda.
neiker



4

Oto świetne wyjaśnienie na ten temat!

Wprowadza również opóźnienia ładowania i limity czasu!

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


Odpowiedzi zawierające tylko łącza nie są przydatne i są uważane za niskiej jakości. Rozważ skopiowanie odpowiednich bitów do swojej odpowiedzi, z przypisaniem oczywiście źródła.
random_user_name

@cale_b Żartujesz? Ta odpowiedź ma ponad 7 lat, więc taki komentarz jest nieuzasadniony.
Stuart.Sklinar

Tak, to stara odpowiedź. Chociaż ich sugestia jest ważna. Odpowiedzi, które są jedynie linkami w innym miejscu, są kandydatami do usunięcia. Dalszy czytelnik: meta.stackoverflow.com/q/8259
Rob

Całkowicie się zgadzam, sam moderowałbym sugestiami - ale nie ma sensu mówić o tym 7 lat później. Powinno to być tak moderowane 7 lat temu, a nie 7 lat później.
Stuart.Sklinar

1
@ Stuart.Sklinar - gdybym to widział 7 lat temu, zrobiłbym to :) Znalazłem się tutaj, szukając informacji i widząc to po raz pierwszy. Przepraszam, że cię denerwuję - myślę, że nasze zadania w SO mają być zarządcami strony, co czasami oznacza komentowanie, edytowanie lub ulepszanie starych pytań lub odpowiedzi ...
random_user_name

4

Dla osób korzystających z ASP.NET MVC 5 dodaj ten kod do pliku BundleConfig.cs, aby włączyć CDN dla 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);

4

AKTUALIZACJA:
Ta odpowiedź okazała się błędna. Zobacz komentarze do prawdziwego wyjaśnienia.


Odpowiedzi na większość z was udzielono odpowiedzi, ale co do ostatniej części:

Jakie byłoby niebezpieczeństwo, że obie kopie przejdą?

Tak naprawdę nie ma. Marnowałbyś przepustowość, może dodać kilka milisekund, pobierając drugą bezużyteczną kopię, ale nie ma rzeczywistej szkody, jeśli obie przejdą. Oczywiście należy tego unikać, stosując techniki wymienione powyżej.


5
W rzeczywistości, dwukrotne ładowanie jQuery może powodować wiele problemów, zgodnie z tym pytaniem .
ShadowCat7

dlaczego nie przetestujesz go sam i ręcznie załadujesz bibliotekę jquery dwukrotnie. wtedy odpowiedź zostanie ujawniona.
luke_mclachlan

Dlaczego dokładnie jest tak źle? @ ShadowCat7 czy możesz bardziej szczegółowo określić problemy, które powoduje? Jedyny problem, który widzę wyraźnie zidentyfikowany w łączonym pytaniu, to „czyszczenie wszystkich wcześniej załadowanych wtyczek”. Ale to nie powinno mieć zastosowania do ładowania tego samego pliku jQuery dwa razy jeden po drugim, prawda? Pytam, ponieważ inne rozwiązania lokalnego rozwiązania awaryjnego są tak skomplikowane, a document.write jest w niektórych miejscach oczerniany jako zło .
Bob Stein

2

Zrobiłem Gist, który powinien dynamicznie ładować jQuery, jeśli nie jest już załadowany, a jeśli źródło zawiedzie, przejdzie do awarii (zszyte z wielu odpowiedzi): https://gist.github.com/tigerhawkvok/9673154

Pamiętaj, że planuję aktualizować Gist, ale nie tę odpowiedź, ponieważ jest tego warta!

/* 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 Hosted jQuery

  • Jeśli zależy Ci na starszych przeglądarkach, głównie wersjach IE wcześniejszych niż IE9, jest to najbardziej kompatybilna wersja jQuery
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
  • Jeśli nie zależy ci na oldIE, ten jest mniejszy i szybszy:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>

Plan awaryjny / awaryjny!

  • Tak czy inaczej, powinieneś skorzystać z rezerwowej wersji lokalnej na wypadek, gdyby Google CDN zawiódł (mało prawdopodobne) lub został zablokowany w miejscu, z którego użytkownicy uzyskują dostęp do Twojej witryny (nieco bardziej prawdopodobne), takim jak Iran lub czasami Chiny.
<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>

Odniesienie: http://websitespeedoptimizations.com/ContentDeliveryNetworkPost.aspx


Uwaga: ładowanie skryptów za pomocą niezabezpieczonych protokołów otwiera wektor ataku XSS.
Josh Habdas,

2

Uważam, że powinien uciec od ostatniego <do \ x3C w ciągu. Gdy przeglądarka widzi, uważa to za koniec bloku skryptu (ponieważ parser HTML nie ma pojęcia o JavaScript, nie może rozróżnić między czymś, co pojawia się w ciągu znaków, a czymś, co w rzeczywistości ma zakończyć skrypt element). Tak więc pojawienie się dosłownie w JavaScript, który znajduje się na stronie HTML, spowoduje (w najlepszym przypadku) błędy i (w najgorszym przypadku) ogromną lukę w zabezpieczeniach.

<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')) { ...

Lub

if(!window.jQuery){

Nie działa, jeśli wersja cdn nie jest załadowana, ponieważ przeglądarka przejdzie przez ten warunek i podczas pobierania nadal pobierze resztę skryptów JavaScript, które wymagają jQuery i zwróci błąd. Rozwiązaniem było załadowanie skryptów przez ten warunek.

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

Znalazłem jeden problem podczas testowania skryptów w Google Chrome - buforowanie. Więc do testowania lokalnego po prostu zamień src w sekcji else na coś takiego jak s.src = 'my_javascripts.js' + '?' + Math.floor (Math.random () * 10001);
Mirek Komárek

Odpowiedź Alexa nie zadziała, jeśli wersja cdn nie zostanie załadowana, ponieważ przeglądarka będzie działać przez ten warunek i podczas pobierania nadal będzie pobierać resztę skryptów JavaScript, które wymagają jquery i zwraca błąd -> pobrane pliki JavaScript zablokują uruchomienie następnego fragmentu kodu więc to nie jest problem .
alex

2

Prawie wszystkie publiczne sieci CDN są dość niezawodne. Jeśli jednak martwisz się zablokowaną domeną google, możesz po prostu wrócić do alternatywnego CDN jQuery . W takim przypadku możesz jednak zrobić to odwrotnie i użyć innej CDN jako preferowanej opcji i wrócić do Google CDN, aby uniknąć nieudanych żądań i czasu oczekiwania:

<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

Korzystając ze składni Razor w ASP.NET, ten kod zapewnia obsługę rezerwową i działa z wirtualnym katalogiem głównym:

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

Lub stwórz pomocnika ( przegląd pomocnika ):

@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>")
}

i użyj tego w ten sposób:

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

Nigdy nie myślę o Razor, ale wygląda jak zaciemniacz, z tym wyjątkiem, że sprawia, że ​​kod jest dłuższy niż krótszy (jest dwa razy dłuższy niż ten .
maaartinus

@maaartinus: To nie jest porównanie jabłek z jabłkami. Odpowiedź Benjamina RH, do której się odwołujesz, dotyczy jednego skryptu hostowanego przez CDN. Z CdnScriptpomocnikiem potrzebujesz tylko jednego wiersza kodu na skrypt . Im więcej masz skryptów, tym większa wypłata.
Edward Brey

Jasne ... to był tylko rant. Myślę jednak, że nie jest to optymalny sposób. Jeśli coś się nie powiedzie, zignoruję CDN całkowicie i przejdę do rezerwowych wszystkich skryptów. Nie jestem pewien, czy jest to wykonalne, ponieważ nie wiem, jak dokładnie działa ładowanie.
maaartinus

@maaartinus: Ponieważ każde ładowanie skryptu CDN może się nie powieść niezależnie, każde ładowanie należy sprawdzić osobno. Nie ma niezawodnej metody pojedynczej kontroli CDN, po której następuje załadowanie wszystkich skryptów z CDN vs. lokalnie.
Edward Brey

Martwi mnie przypadek awarii strony CDN, co prowadzi do czasów oczekiwania na wiele ładunków. Więc chciałbym mieć coś takiego try { for (Script s : ...) cdnLoad(s); } catch (...) { for (Script s : ...) ownLoad(s); }. Przełożenie tego na kilka ifs może być koszmarem.
maaartinus

1

Chociaż pisanie document.write("<script></script>")wydaje się łatwiejsze do wycofania jQuery, Chrome daje błąd sprawdzania poprawności w tym przypadku. Wolę więc łamać słowo „skrypt”. Staje się więc bezpieczniejszy jak wyżej.

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

W przypadku problemów długoterminowych lepiej byłoby zarejestrować awarie JQuery. W powyższym kodzie, jeśli pierwszy CDN nie jest dostępny, JQuery jest ładowany z innego CDN. Ale możesz chcieć poznać ten błędny CDN i usunąć go na stałe. (ten przypadek jest bardzo wyjątkowy). Lepiej jest także rejestrować problemy zastępcze. Dzięki temu możesz wysyłać błędne skrzynki za pomocą AJAX. Ponieważ JQuery nie jest zdefiniowany, powinieneś używać waniliowego javascript do żądania 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

Jeszcze jedna awaria zastępująca ajax.googleapis.com przez 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);
  • Możesz trzymać się wersji jQuery, określając ją w ciągu
  • Idealny do zarządzania zasobami, który nie działa z wycinkami HTML
  • Testowany na wolności - działa idealnie dla użytkowników z Chin

Czy mógłbyś rozwinąć następujące zdanie: „Nie musisz się przejmować wersją jQuery”?
Josh Habdas,

Wersja jest częścią adresu URL, który nie jest dotknięty tym podejściem ... jquery / 3.xx / jquery.min.js
redaxmedia

1
Czy może to spowodować uszkodzenie, gdy jQuery powróci do wersji 4 i wprowadzi niezgodne wstecz zmiany?
Josh Habdas

-1, ponieważ spowoduje to zerwanie, jeśli jQuery wprowadzi zmiany, których skrypty nie będą jeszcze obsługiwane, chyba że wersja zostanie określona.
Lookaji

@lookaji Myślę, że nie rozumiesz awarii. Zastępuje domenę, w której jest hostowany, i wcale NIE dotyka nazwy pliku / wersji.
redaxmedia

0

Możesz użyć kodu takiego jak:

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

Ale są też biblioteki, których można użyć do skonfigurowania kilku możliwych błędów w skryptach i zoptymalizowania procesu ładowania:

  • basket.js
  • Wymagaj JS
  • yepnope

Przykłady:

basket.js Myślę, że na razie najlepszy wariant. Zapisuje twój skrypt w localStorage, co przyspieszy kolejne ładowanie. Najprostsze połączenie:

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

To zwróci obietnicę i możesz wykonać następne wywołanie w przypadku błędu lub załadować zależności od sukcesu:

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

Wymagaj 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

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');
    }
  }
}]);
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.