Cara terbaik untuk menggunakan jQuery yang dihosting Google, tetapi kembali ke pustaka yang dihosting di Google gagal

1016

Apa cara yang baik untuk mencoba memuat jQuery yang dihosting di Google (atau lib Google yang dihosting Google), tetapi muat salinan jQuery saya jika upaya Google gagal?

Saya tidak mengatakan Google tidak stabil. Ada kasus di mana salinan Google diblokir (misalnya di Iran, misalnya).

Apakah saya akan mengatur timer dan memeriksa objek jQuery?

Apa bahaya kedua salinan itu?

Tidak benar-benar mencari jawaban seperti "gunakan saja Google" atau "gunakan saja sendiri." Saya mengerti argumen itu. Saya juga mengerti bahwa pengguna cenderung memiliki cache versi Google. Saya berpikir tentang fallback untuk cloud secara umum.


Edit: Bagian ini ditambahkan ...

Karena Google menyarankan untuk menggunakan google.load untuk memuat pustaka ajax, dan melakukan panggilan balik ketika selesai, saya bertanya-tanya apakah itu kunci untuk membuat serialisasi masalah ini.

Saya tahu ini terdengar agak gila. Saya hanya mencoba mencari tahu apakah itu dapat dilakukan dengan cara yang dapat diandalkan atau tidak.


Pembaruan: jQuery sekarang di-host di CDN Microsoft.

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

Nosredna
sumber
9
Tentu saja jawaban pertama adalah "jangan gunakan versi google-host." :-)
Nosredna
7
Tentu saja itu karena jika Anda ingin meng-host situs web yang serius, Anda tidak bergantung pada orang lain yang meng-hosting file Anda.
Bryan Migliorisi
6
@Bryan Migliorisi, saya kira Twitter tidak seserius itu? Tapi saya akui mereka punya masalah dengan Google seperti sebulan yang lalu ketika Google turun.
Ionuț G. Stan
18
Manfaat menggunakan Google atau tidak untuk hosting JS lib adalah layak, tetapi telah dibahas di beberapa utas lainnya. Saya mencari jawaban teknis tentang fallback JS pada penundaan pemuatan.
Nosredna
2
@ Jo Chung: Kemungkinan besar akan di-cache pada sistem pengguna, mempercepat pemuatan halaman. Menghemat saya bandwidth. Menggunakan CDN Google. Dll
Nosredna

Jawaban:

810

Anda dapat mencapainya seperti ini:

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

Ini harus di halaman Anda <head>dan penangan acara siap jQuery harus di <body>untuk menghindari kesalahan (meskipun itu bukan bukti bodoh!).

Satu lagi alasan untuk tidak menggunakan jQuery yang dihosting Google adalah bahwa di beberapa negara, nama domain Google dilarang.

Rony
sumber
35
Bukankah unduhan javascript sudah memblokir (sinkron)? Menurut saya masalah duplikat karenanya tidak akan menjadi masalah.
Matt Sherman
68
Unduhan Javascript harus sudah sinkron, seperti kata Matt Sherman. Jika tidak, banyak masalah akan terjadi jika halaman mencoba mengeksekusi skrip inline yang bergantung pada pustaka yang hanya setengah diunduh, atau ekstensi pustaka dijalankan tanpa pustaka sepenuhnya diunduh dan dieksekusi. Itu juga salah satu alasan mengapa Yahoo YSlow merekomendasikan menempatkan javascript di akhir halaman; sehingga tidak memblokir pengunduhan elemen halaman lainnya (termasuk gaya dan gambar). Paling tidak, browser harus menunda eksekusi agar terjadi secara berurutan.
gapple
42
Perbaikan kecil dari fanatik validator: String '</' tidak diizinkan dalam JavaScript, karena itu bisa disalahartikan sebagai akhir tag skrip (notasi tag pendek SGML). Lakukan '<' + '/ skrip>' sebagai gantinya. Cheers,
Boldewyn
8
Contoh ini tidak akan berfungsi. 1) jika pustaka ajax Google tidak tersedia, ia harus keluar dulu sebelum gagal. Ini mungkin memakan waktu cukup lama. Dalam pengujian saya melepaskan komputer saya dari jaringan itu hanya mencoba dan mencoba dan mencoba dan tidak kehabisan waktu. 2) jika (! JQuery) akan melempar kesalahan karena jQuery tidak didefinisikan sehingga Javascript tidak tahu apa yang harus dilakukan dengannya.
RedWolves
32
Untuk menguji apakah jQuery dimuat, (! Window.jQuery) berfungsi dengan baik, dan disingkat maka jenis pemeriksaan.
Jörn Zaefferer
335

Cara termudah dan terbersih untuk melakukan ini sejauh ini:

<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>
BenjaminRH
sumber
1
@ jpp bukan untuk XHTML 1.0danHTML 4.01
BenjaminRH
5
Orang-orang terus meminta saya untuk menghapus type="text/javascript"bagian - bagiannya, jadi kepada orang-orang yang menulis html untuk peramban yang lebih lama, perhatikan bahwa Anda sekarang harus menambahkannya.
BenjaminRH
6
@BenjaminRH: type="text/javascript"juga tidak perlu di browser lama, karena semuanya default ke Javascript. Peramban yang benar - benar lebih tua melihat languageatributnya; tetapi bahkan kemudian, Javascript adalah default jika atributnya hilang.
Martijn
1
@ Martijn Tapi saya menyukai lencana validasi yang mengkilap :)
BenjaminRH
3
@ Trojan Sangat mungkin, hanya menumpuk panggilan. Perhatikan bahwa pada titik ini Anda sedang membuka host koneksi baru, jadi pipelining HTTP mungkin akan lebih cepat. ... <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

Ini sepertinya bekerja untuk saya:

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

Cara kerjanya adalah dengan menggunakan googleobjek yang memanggil http://www.google.com/jsapi memuat ke windowobjek. Jika objek itu tidak ada, kami mengasumsikan bahwa akses ke Google gagal. Jika demikian, kami memuat salinan lokal menggunakan document.write. (Saya menggunakan server saya sendiri dalam hal ini, silakan gunakan server Anda sendiri untuk menguji ini).

Saya juga menguji keberadaan window.google.load- Saya juga bisa melakukan typeofpemeriksaan untuk melihat bahwa benda-benda adalah benda atau fungsi yang sesuai. Tapi saya pikir ini yang berhasil.

Berikut ini hanya logika pemuatan, karena penyorotan kode tampaknya gagal karena saya memposting seluruh halaman HTML yang saya uji:

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

Meskipun saya harus mengatakan, saya tidak yakin bahwa jika ini menjadi perhatian bagi pengunjung situs Anda, Anda harus mengutak-atik API Perpustakaan Google AJAX sama sekali.

Fakta menyenangkan : Saya awalnya mencoba menggunakan blok try..catch untuk ini dalam berbagai versi tetapi tidak dapat menemukan kombinasi yang sebersih ini. Saya tertarik untuk melihat implementasi lain dari ide ini, murni sebagai latihan.

artlung
sumber
1
Apa keuntungan menggunakan google.load dalam situasi ini, daripada memuat ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js secara langsung, seperti yang disarankan Rony? Saya kira memuatnya langsung menangkap masalah dengan pustaka yang dihapus juga (bagaimana jika Google berhenti melayani JQuery 1.3.2). Lebih jauh, versi Rony memperhatikan masalah jaringan SETELAH www.google.com/jsapi telah diambil, terutama ketika jsapi telah diambil dari cache? Orang mungkin perlu menggunakan panggilan balik google.load untuk memastikan (atau mungkin ada beberapa nilai balik untuk menyertakan google.load di if (..)).
Arjan
Jika seseorang menguji keberadaan Google.com, seseorang dapat melakukan panggilan jaringan, atau seseorang dapat memeriksa keberadaan objek "gatekeeper". Apa yang saya lakukan adalah memeriksa objek google dan fungsinya "memuat". Jika keduanya gagal, tidak ada google, dan saya memerlukan versi lokal. Versi Rony sebenarnya mengabaikan URL www.google.com/jsapi sepenuhnya, jadi saya tidak yakin mengapa Anda mengindikasikan bahwa URL itu telah diambil.
artlung
Pada akhirnya, semua yang diperlukan adalah bahwa perpustakaan jquery dimuat. Pustaka Google apa pun bukan keharusan. Dalam jawaban Rony, orang tahu pasti apakah memuat dari Google (atau cache) berhasil. Tetapi dalam pemeriksaan Anda untuk "jika (window.google && window.google.load)", pustaka jquery masih belum dimuat. Pemuatan aktual perpustakaan jquery tidak divalidasi?
Arjan
ah, saya mengerti bagaimana saya menyebabkan kebingungan. "Versi Rony memperhatikan masalah jaringan SETELAH www.google.com/jsapi telah diambil" sebaiknya membaca: "Versi Anda tidak melihat masalah jaringan SETELAH www.google.com/jsapi telah diambil".
Arjan
2
Kami baru-baru ini beralih menggunakan Google sebagai host jQuery kami; jika kami mendapatkan laporan bug dari pengguna yang diblokir, saya akan menggunakan varian jawaban Anda untuk membuat ulang kode klien kami. Jawaban yang bagus!
Jarrod Dixon
30

Jika Anda memiliki modernizr.js tertanam di situs Anda, Anda dapat menggunakan yepnope.js bawaan untuk memuat skrip Anda secara tidak sinkron - antara lain jQuery (dengan fallback).

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

Ini memuat jQuery dari Google-cdn. Setelah itu diperiksa, apakah jQuery berhasil dimuat. Jika tidak ("nggak"), versi lokal dimuat. Juga skrip pribadi Anda dimuat - "keduanya" menunjukkan, bahwa proses memuat dimulai secara independen dari hasil tes.

Ketika semua proses memuat selesai, fungsi dijalankan, dalam kasus 'MyApp.init'.

Saya pribadi lebih suka cara memuat skrip asinkron ini. Dan karena saya mengandalkan fitur-tes yang disediakan oleh modernizr ketika membangun sebuah situs, saya tetap melekat pada situs tersebut. Jadi sebenarnya tidak ada overhead.

Emanuel Kluge
sumber
2
Saya pikir Anda melewatkan inti pertanyaan - bagaimana Anda bisa memuat skrip moernizr dari CDN?
George Filippakos
2
Saya tidak bisa merekomendasikan memuat Modernizr dari CDN. Orang lebih suka mendapatkan bangunan kustom terkecil dari modernizr.com.
Emanuel Kluge
2
Jadi opsi ini mendapat +16, dibandingkan dengan 500/200 + opsi lain yang didapat. Tapi ini kedengarannya bagus. Apakah ini tidak populer karena mengandalkan Modernizer? Saya kebetulan menggunakan Modernizer di situs kami, jadi jika ini lebih baik daripada jawaban yang lain, bisakah seseorang memberi tahu saya? Saya cukup baru di JQuery, jadi klarifikasi sangat dihargai.
redfox05
2
Ini adalah pilihan yang sangat bagus pada saat jawabannya, tetapi pada 2015, yepnope.jssudah usang. lihat stackoverflow.com/questions/33986561/…
Obmerk Kronen
Modernizr diciptakan untuk menyelesaikan masalah seperti pertanyaan ini. +1
Carlos Quijano
21

Ada beberapa solusi hebat di sini, tetapi saya ingin mengambil satu langkah lebih jauh mengenai file lokal.

Dalam skenario ketika Google gagal, seharusnya memuat sumber lokal tetapi mungkin file fisik di server tidak selalu merupakan pilihan terbaik. Saya membawa ini karena saya sedang mengimplementasikan solusi yang sama, hanya saja saya ingin kembali ke file lokal yang dihasilkan oleh sumber data.

Alasan saya untuk ini adalah bahwa saya ingin memiliki beberapa pemikiran ketika datang untuk melacak apa yang saya muat dari Google vs apa yang saya miliki di server lokal. Jika saya ingin mengubah versi, saya ingin agar salinan lokal saya tetap disinkronkan dengan apa yang saya coba muat dari Google. Dalam lingkungan di mana ada banyak pengembang, saya pikir pendekatan terbaik adalah mengotomatiskan proses ini sehingga yang harus dilakukan adalah mengubah nomor versi dalam file konfigurasi.

Inilah solusi yang saya usulkan yang seharusnya bekerja secara teori:

  • Dalam file konfigurasi aplikasi, saya akan menyimpan 3 hal: URL absolut untuk perpustakaan, URL untuk JavaScript API, dan nomor versi
  • Tulis kelas yang mendapatkan isi file perpustakaan itu sendiri (dapatkan URL dari konfigurasi aplikasi), simpan di sumber data saya dengan nama dan nomor versi
  • Tulis pawang yang menarik file lokal saya keluar dari db dan cache file sampai nomor versi berubah.
  • Jika itu berubah (dalam konfigurasi aplikasi saya), kelas saya akan menarik konten file berdasarkan nomor versi, menyimpannya sebagai catatan baru di sumber data saya, maka pawang akan menendang dan menyajikan versi baru.

Secara teori, jika kode saya ditulis dengan benar, semua yang perlu saya lakukan adalah mengubah nomor versi di konfigurasi aplikasi saya kemudian viola! Anda memiliki solusi cadangan yang otomatis, dan Anda tidak perlu memelihara file fisik di server Anda.

Apa yang dipikirkan semua orang? Mungkin ini berlebihan, tetapi bisa menjadi metode yang elegan untuk mempertahankan perpustakaan AJAX Anda.

Biji pohon ek

Biji pohon ek
sumber
Jika Anda melakukan semua pekerjaan itu hanya untuk jQuery, maka saya akan mengatakan itu berlebihan. Namun, jika Anda sudah memiliki beberapa komponen tersebut di tempat untuk bagian lain dari aplikasi Anda (misalnya jika Anda sudah memuat skrip dari DB) maka itu terlihat cukup bagus.
Michael Haren
1
+1 karena teliti dan novel, meskipun saya tidak yakin manfaatnya membenarkan waktu dan kompleksitas dev.
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);

}

Setelah Anda mencoba untuk memasukkan salinan Google dari CDN.

Di HTML5, Anda tidak perlu mengatur typeatribut.

Anda juga bisa menggunakan...

window.jQuery || document.write('<script src="/libs/jquery.js"><\/script>');
alex
sumber
2
+1 terlihat lebih bersih. ada kesalahan ketik kecil di atas yang saya tidak dapat menghapus karena kurung tutup dua kecil yang mati setelah 'tidak terdefinisi'
naveen
1
Opsi pertama menghindari peringatan Chrome[Violation] Avoid using document.write().
Bob Stein
Opsi pertama, sayangnya, tampaknya tidak memuat secara sinkron . Opsi kedua tidak .
Bob Stein
10

Anda mungkin ingin menggunakan file lokal Anda sebagai pilihan terakhir.

Tampaknya CDN jQuery sekarang tidak mendukung https. Jika itu Anda mungkin ingin memuat dari sana dulu.

Jadi inilah urutannya: Google CDN => Microsoft CDN => Salinan lokal Anda.

<!-- 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> 
Edward Olamisan
sumber
Apakah benar-benar diperlukan lebih dari satu kali mundur? jika keduanya offline, pengguna akan menunggu lebih dari satu menit sebelum melihat situs Anda
George Filippakos
1
Tidak perlu 1 menit untuk skrip gagal memuat, bukan.
Edward Olamisan
@ geo1701 dan Edward, benar-benar tidak perlu untuk yang ketiga. Bahkan satu fallback belum terbukti andal. Jika Google API tidak berfungsi, saya belum melihat adanya jaminan bahwa upaya pertama akan gagal sama sekali. Saya mengalami skenario kasus di mana CDN tidak pernah gagal memuat, menahan halaman agar tidak pernah dirender, seperti yang disebutkan di sini: stevesouders.com/blog/2013/03/18/http-archive-jquery/…
hexalys
6

Persyaratan memuat versi / fallback jQuery terbaru / lama:

<!--[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]-->
neiker
sumber
Ini tidak kompatibel lintas-browser.
Josh Habdas
Josh, ya, benar.
neiker
4

Ini penjelasan yang bagus tentang ini!

Juga mengimplementasikan penundaan pemuatan dan batas waktu!

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

Stuart. Sklinar
sumber
Jawaban hanya tautan tidak berguna dan dianggap berkualitas rendah. Pertimbangkan menyalin bit yang relevan ke dalam jawaban Anda, tentu saja dengan atribusi ke sumbernya.
random_user_name
@cale_b Apakah Anda bercanda? Jawaban ini sudah lebih dari 7 tahun, jadi komentar seperti itu tidak beralasan.
Stuart. Sklinar
Ya, itu jawaban lama. Padahal saran mereka valid. Jawaban yang hanya berupa tautan di tempat lain adalah kandidat untuk dihapus. Pembaca lebih lanjut: meta.stackoverflow.com/q/8259
Rob
Saya setuju sepenuhnya, saya sendiri akan memoderasi saran - tetapi tidak ada gunanya mengatakannya 7 tahun kemudian. Seharusnya dimoderasi seperti itu 7 tahun lalu, bukan 7 tahun kemudian.
Stuart.Sklinar
1
@ Stuart.Sklinar - jika saya melihatnya 7 tahun yang lalu, saya pasti :) Saya menemukan diri saya di sini melakukan penelitian, dan melihat ini untuk pertama kalinya. Maaf membuat Anda frustrasi - Saya pikir pekerjaan kami di SO adalah menjadi pelayan situs, yang terkadang berarti berkomentar, mengedit, atau meningkatkan pertanyaan atau jawaban lama ...
random_user_name
4

Bagi mereka yang menggunakan ASP.NET MVC 5, tambahkan kode ini di BundleConfig.cs Anda untuk mengaktifkan CDN untuk 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);
Muhammad Rehan Saeed
sumber
4

UPDATE:
Jawaban ini ternyata salah. Silakan lihat komentar untuk penjelasan yang sebenarnya.


Sebagian besar dari Anda pertanyaan telah dijawab, tetapi untuk bagian terakhir:

Apa bahaya kedua salinan itu?

Tidak ada yang benar-benar. Anda akan membuang bandwidth, mungkin menambahkan beberapa milidetik mengunduh salinan kedua yang tidak berguna, tetapi tidak ada salahnya jika keduanya terjadi. Anda harus, tentu saja, menghindari ini menggunakan teknik yang disebutkan di atas.

WhyNotHugo
sumber
5
Sebenarnya, memuat jQuery dua kali dapat menyebabkan banyak masalah, menurut pertanyaan ini .
ShadowCat7
mengapa Anda tidak mengujinya sendiri dan memuat pustaka jquery secara manual dua kali. maka jawabannya akan terungkap.
luke_mclachlan
Kenapa itu sangat salah? @ ShadowCat7 dapatkah Anda lebih spesifik tentang masalah yang ditimbulkannya? Satu-satunya masalah yang saya lihat diidentifikasi secara eksplisit dalam pertanyaan yang Anda tautkan adalah "menghapus semua plugin yang dimuat sebelumnya." Tapi itu seharusnya tidak berlaku untuk memuat file jQuery yang sama dua kali back-to-back, kan? Saya bertanya karena solusi lain di sini untuk fallback lokal sangat berbelit-belit, dan dokumen. Penulisan difitnah sebagai kejahatan di beberapa tempat .
Bob Stein
2

Saya membuat intisari yang seharusnya secara dinamis memuat jQuery jika belum dimuat, dan jika sumber gagal, ia melanjutkan ke fallback (dijahit bersama dari banyak jawaban): https://gist.github.com/tigerhawkvok/9673154

Harap dicatat saya berencana untuk terus memperbarui Gist tetapi bukan jawaban ini, untuk apa nilainya!

/* 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();
}
Philip Kahn
sumber
2

Google Hosted jQuery

  • Jika Anda peduli dengan browser lama, terutama versi IE sebelum IE9, ini adalah versi jQuery paling kompatibel
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
  • Jika Anda tidak peduli dengan oldIE, yang ini lebih kecil dan lebih cepat:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>

Paket Cadangan / Fallback!

  • Either way, Anda harus menggunakan fallback ke lokal kalau-kalau Google CDN gagal (tidak mungkin) atau diblokir di lokasi di mana pengguna Anda mengakses situs Anda (sedikit lebih mungkin), seperti Iran atau kadang-kadang Cina.
<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>

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

Ryan
sumber
Catatan memuat skrip melalui protokol tidak aman membuka vektor serangan XSS.
Josh Habdas
2

Saya menganggap bahwa harus keluar dari string <to \ x3C terakhir. Ketika browser melihat, itu menganggap ini sebagai akhir dari blok skrip (karena parser HTML tidak tahu tentang JavaScript, itu tidak dapat membedakan antara sesuatu yang hanya muncul dalam string, dan sesuatu yang sebenarnya dimaksudkan untuk mengakhiri skrip elemen). Jadi muncul secara harfiah di JavaScript yang ada di dalam halaman HTML akan (dalam kasus terbaik) menyebabkan kesalahan, dan (dalam kasus terburuk) menjadi lubang keamanan yang sangat besar.

<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>
JKhuang
sumber
2
if (typeof jQuery == 'undefined')) { ...

Atau

if(!window.jQuery){

Tidak akan berfungsi jika versi cdn tidak dimuat, karena browser akan berjalan melalui kondisi ini dan selama itu masih mengunduh sisa javascripts yang memerlukan jQuery dan mengembalikan kesalahan. Solusi adalah memuat skrip melalui kondisi itu.

    <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>
Mirek Komárek
sumber
Saya menemukan satu masalah dalam pengujian skrip di Google Chrome - caching. Jadi untuk pengujian lokal, ganti src di bagian lain dengan sesuatu seperti s.src = 'my_javascripts.js' + '?' + Math.floor (Math.random () * 10001);
Mirek Komárek
Jawaban Alex tidak akan berfungsi jika versi cdn tidak dimuat, karena browser akan berjalan melalui kondisi ini dan selama itu masih mengunduh sisa javascripts yang memerlukan jquery dan mengembalikan kesalahan -> File JavaScript yang diunduh akan memblokir bagian kode berikutnya yang tidak dijalankan jadi itu bukan masalah .
alex
2

Hampir semua CDN publik cukup andal. Namun, jika Anda khawatir tentang domain google yang diblokir, maka Anda dapat dengan mudah mundur ke CDN jQuery alternatif . Namun, dalam kasus seperti itu, Anda dapat memilih untuk melakukannya secara berlawanan dan menggunakan beberapa CDN lain sebagai opsi pilihan dan mundur ke Google CDN untuk menghindari permintaan yang gagal dan waktu tunggu:

<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>
Hamid Sarfraz
sumber
1

Menggunakan sintaks Razor di ASP.NET, kode ini memberikan dukungan fallback dan bekerja dengan root virtual:

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

Atau buat helper ( gambaran umum helper ):

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

dan gunakan seperti ini:

@CdnScript("jquery-1.7.1.min.js", "ajax/jQuery", "window.jQuery")
@CdnScript("jquery.validate.min.js", "ajax/jquery.validate/1.9", "jQuery.fn.validate")
Edward Brey
sumber
Saya tidak pernah peduli dengan Razor, tetapi kelihatannya seperti obfuscator, kecuali untuk itu membuat kode lebih panjang daripada pendek (ini dua kali lebih lama dari ini .
maaartinus
@maaartinus: Itu bukan perbandingan apel dengan apel. Jawaban BenjaminRH, yang Anda rujuk, adalah untuk satu skrip yang di-host CDN. Dengan CdnScripthelper, Anda hanya perlu satu baris kode per skrip . Semakin banyak skrip yang Anda miliki, semakin besar hasilnya.
Edward Brey
Tentu ... itu hanya kata-kata kasar. Namun, saya kira itu bukan cara yang optimal. Jika ada yang gagal, saya akan mengabaikan CDN sepenuhnya dan beralih ke fallback untuk semua skrip. Saya tidak yakin apakah ini bisa dilakukan karena saya tidak tahu bagaimana cara memuatnya.
maaartinus
@maaartinus: Karena setiap pemuatan skrip CDN dapat gagal secara independen, Anda harus memeriksa setiap pemuatan secara terpisah. Tidak ada metode yang dapat diandalkan dari pemeriksaan CDN tunggal diikuti dengan memuat semua skrip dari CDN vs lokal.
Edward Brey
Kasus yang membuat saya khawatir adalah kegagalan situs CDN yang menyebabkan waktu menunggu untuk banyak muatan. Jadi saya ingin memiliki sesuatu seperti try { for (Script s : ...) cdnLoad(s); } catch (...) { for (Script s : ...) ownLoad(s); }. Menerjemahkan ini ke sekelompok ifs bisa menjadi mimpi buruk.
maaartinus
1

Meskipun penulisan document.write("<script></script>")tampaknya lebih mudah untuk backoff jQuery, Chrome memberikan kesalahan validasi pada kasus itu. Jadi saya lebih suka melanggar kata "skrip". Sehingga menjadi lebih aman seperti di atas.

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

Untuk masalah jangka panjang, akan lebih baik untuk mencatat fallback JQuery. Dalam kode di atas, jika CDN pertama tidak tersedia JQuery diambil dari CDN lain. Tapi Anda mungkin ingin tahu CDN yang salah dan menghapusnya secara permanen. (kasus ini adalah kasus yang sangat luar biasa) Juga lebih baik untuk mencatat masalah fallback. Jadi, Anda dapat mengirim kasus yang salah dengan AJAX. Karena JQuery tidak didefinisikan, Anda harus menggunakan javascript vanilla untuk permintaan 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>
trante
sumber
0

Namun fallback lain yang menggantikan ajax.googleapis.com dengan 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);
  • Anda bisa tetap menggunakan versi jQuery dengan menentukannya di string
  • Sempurna untuk Manajemen Aset yang tidak berfungsi dengan snips HTML
  • Diuji di alam liar - berfungsi sempurna untuk pengguna dari Cina
redaxmedia
sumber
Bisakah Anda menguraikan pernyataan berikut: "Anda tidak perlu peduli dengan versi jQuery"?
Josh Habdas
Versi ini adalah bagian dari URL yang tidak akan disentuh oleh pendekatan ini ... jquery / 3.xx / jquery.min.js
redaxmedia
1
Apakah itu berpotensi menyebabkan kerusakan ketika jQuery revs ke versi 4 dan memperkenalkan perubahan mundur yang tidak kompatibel?
Josh Habdas
-1 karena itu akan menyebabkan kerusakan jika jQuery memperkenalkan perubahan yang tidak dapat didukung skrip Anda kecuali versi tersebut ditentukan.
Lookaji
@lookaji Saya pikir Anda tidak mengerti fallback. Itu mengganti domain di mana ia di-host dan TIDAK menyentuh nama file / versi sama sekali.
redaxmedia
0

Anda dapat menggunakan kode seperti:

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

Tetapi juga ada perpustakaan yang dapat Anda gunakan untuk mengatur beberapa kemungkinan fallback untuk skrip Anda dan mengoptimalkan proses pemuatan:

  • basket.js
  • Membutuhkan JS
  • ya tidak

Contoh:

basket.js saya pikir varian terbaik untuk saat ini. Akan menghapus naskah Anda di localStorage, yang akan mempercepat pemuatan berikutnya. Panggilan paling sederhana:

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

Ini akan mengembalikan janji dan Anda dapat melakukan kesalahan panggilan berikutnya, atau memuat dependensi pada kesuksesan:

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

Membutuhkan 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 ($) {
});

ya tidak

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');
    }
  }
}]);
Роман Коптев
sumber