A melhor maneira de usar o jQuery hospedado pelo Google, mas voltar à minha biblioteca hospedada no Google falha

1016

Qual seria uma boa maneira de tentar carregar o jQuery hospedado no Google (ou em outras bibliotecas hospedadas pelo Google), mas carregar minha cópia do jQuery se a tentativa do Google falhar?

Não estou dizendo que o Google é esquisito. Há casos em que a cópia do Google é bloqueada (aparentemente no Irã, por exemplo).

Eu configuraria um timer e verificaria o objeto jQuery?

Qual seria o perigo das duas cópias aparecerem?

Na verdade, não estou procurando respostas como "basta usar o do Google" ou "apenas o seu". Eu entendo esses argumentos. Também entendo que é provável que o usuário tenha a versão do Google em cache. Estou pensando em fallbacks para a nuvem em geral.


Editar: Esta parte foi adicionada ...

Como o Google sugere o uso do google.load para carregar as bibliotecas ajax, e ele executa um retorno de chamada quando concluído, pergunto-me se essa é a chave para serializar esse problema.

Eu sei que parece um pouco louco. Só estou tentando descobrir se isso pode ser feito de maneira confiável ou não.


Atualização: o jQuery agora está hospedado na CDN da Microsoft.

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

Nosredna
fonte
9
Obviamente, a primeira resposta foi "não use a versão hospedada no Google". :-)
Nosredna
7
Claro que foi porque se você deseja hospedar um site sério, não confia em outra pessoa que hospeda seus arquivos.
18711 Bryan Migliorisi
6
@Bryan Migliorisi, acho que o Twitter não é tão sério, afinal? Mas admito que eles tiveram seus problemas com o Google há um mês atrás, quando o Google caiu.
Ionuţ G. Stan
18
O mérito de usar o Google ou não para a hospedagem JS lib é digno, mas foi discutido em vários outros tópicos. Eu estava procurando respostas técnicas sobre o fallback do JS nos atrasos no carregamento.
Nosredna
2
@ Joe Chung: É provável que seja armazenado em cache no sistema do usuário, acelerando o carregamento da página. Economiza-me largura de banda. Usa o CDN do Google. Etc.
Nosredna

Respostas:

810

Você pode conseguir assim:

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

Isso deve estar na sua página <head>e qualquer manipulador de eventos pronto para jQuery deve estar no <body>para evitar erros (embora não seja à prova de idiotas!).

Mais um motivo para não usar o jQuery hospedado pelo Google é que, em alguns países, o nome de domínio do Google é proibido.

Rony
fonte
35
Os downloads de javascript já não estão bloqueando (síncrona)? Parece-me que a questão da cópia dupla não seria um problema.
Matt Sherman
68
Os downloads de Javascript já devem ser síncronos, como Matt Sherman disse. Caso contrário, muitos problemas ocorreriam se a página tentasse executar um script embutido que dependesse de uma biblioteca que foi baixada apenas pela metade ou se uma extensão da biblioteca fosse executada sem que a biblioteca fosse baixada e executada completamente. Essa também é uma das razões pelas quais o Yahoo YSlow recomenda colocar o javascript no final das páginas; para não bloquear o download de outros elementos da página (incluindo estilos e imagens). No mínimo, o navegador precisaria atrasar a execução para ocorrer sequencialmente.
gapple
42
Correção pequena de um fanático do validador: A cadeia '</' não é permitida no JavaScript, pois pode ser mal interpretada como o final da marca de script (notação de marca curta SGML). Faça '<' + '/ script>'. Cheers,
Boldewyn
8
Este exemplo não irá funcionar. 1) se a biblioteca do Google ajax não estiver disponível, será necessário esgotar o tempo limite antes de falhar. Isso pode demorar um pouco. No meu teste de desconectar meu computador da rede, ele tentou e tentou e tentou e não atingiu o tempo limite. 2) if (! JQuery) gerará um erro porque o jQuery não está definido, portanto o Javascript não sabe o que fazer com ele.
RedWolves
32
Para testar se o jQuery foi carregado, (! Window.jQuery) funciona bem e recebe um curto-circuito na verificação de tipo.
Jörn Zaefferer
335

A maneira mais fácil e limpa de fazer isso de longe:

<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
fonte
1
@jpp não é para XHTML 1.0eHTML 4.01
BenjaminRH
5
As pessoas continuam a perguntar-me para remover as type="text/javascript"partes, de modo que as pessoas escrevendo html para navegadores mais antigos, nota que você vai agora ter de acrescentar que no.
BenjaminRH
6
@BenjaminRH: type="text/javascript"também não era necessário em navegadores mais antigos, pois todos eram padronizados para Javascript. Navegadores realmente mais antigos examinaram o languageatributo; mas, mesmo assim, o Javascript era o padrão se o atributo estivesse ausente.
Martijn
1
@Martijn Mas eu gostei do emblema validação brilhante :)
BenjaminRH
3
@ Trojan Totalmente possível, basta empilhar as chamadas. Observe que, neste ponto, você está abrindo novos hosts de conexões, portanto o pipelining HTTP provavelmente será mais rápido. ... <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

Isso parece funcionar para mim:

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

A maneira como funciona é usar o googleobjeto carregado por http://www.google.com/jsapi no windowobjeto. Se esse objeto não estiver presente, estamos assumindo que o acesso ao Google está falhando. Se for esse o caso, carregamos uma cópia local usando document.write. (Neste caso, estou usando meu próprio servidor, use o seu próprio para testar isso).

Eu também testo a presença de window.google.load- eu também poderia typeofverificar se as coisas são objetos ou funções, conforme apropriado. Mas acho que isso funciona.

Aqui está apenas a lógica de carregamento, pois o destaque do código parece falhar desde que eu publiquei toda a página HTML que estava testando:

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

Embora eu deva dizer, não tenho certeza de que, se essa é uma preocupação para os visitantes do site, você deve estar brincando com a API de bibliotecas do Google AJAX .

Curiosidade : inicialmente tentei usar um bloco try..catch em várias versões, mas não consegui encontrar uma combinação tão limpa quanto essa. Eu estaria interessado em ver outras implementações dessa idéia, puramente como um exercício.

artlung
fonte
1
Qual é a vantagem de usar o google.load nessa situação, em vez de carregar ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js diretamente, como sugerido por Rony? Eu acho que carregá-lo diretamente também captura problemas com as bibliotecas removidas (e se o Google parar de servir o JQuery 1.3.2). Além disso, a versão do Rony percebe problemas de rede APÓS o www.google.com/jsapi ter sido buscado, especialmente quando o jsapi é carregado do cache? Pode ser necessário usar o retorno de chamada google.load para ter certeza (ou talvez haja algum valor de retorno para incluir o google.load no if (..)).
Arjan
Se alguém estiver testando a presença do Google.com, poderá fazer uma chamada de rede ou verificar a presença do objeto "gatekeeper". O que estou fazendo é verificar o objeto do Google e sua função "carregar". Se ambos falharem, não há google e preciso da versão local. A versão de Rony realmente ignora completamente o URL www.google.com/jsapi, portanto, não sei por que você indica que ele foi buscado.
Artlung 27/06/2009
No final, tudo o que é necessário é que a biblioteca jquery seja carregada. Qualquer biblioteca do Google não é um requisito. Na resposta de Rony, sabe-se com certeza se o carregamento do Google (ou do cache) foi bem-sucedido. Mas, na verificação de "if (window.google && window.google.load)", a biblioteca jquery ainda não está carregada. O carregamento real da biblioteca jquery não é validado?
22630 Arjan
ah, vejo como causei a confusão. "A versão do Rony percebe problemas de rede APÓS a busca do www.google.com/jsapi" deve ler-se melhor: "Sua versão não percebe problemas de rede APÓS a busca do www.google.com/jsapi".
22430 Arjan
2
Recentemente, passamos a usar o Google como nosso host jQuery; se recebermos relatórios de erros de usuários bloqueados, usarei uma variante da sua resposta para refatorar o código do cliente. Boa resposta!
Jarrod Dixon
30

Se você possui o modernizr.js incorporado em seu site, pode usar o yepnope.js embutido para carregar seus scripts de forma assíncrona - entre outros jQuery (com 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();
    }
}]);

Isso carrega o jQuery do Google-cdn. Depois é verificado, se o jQuery foi carregado com sucesso. Caso contrário ("não"), a versão local é carregada. Além disso, seus scripts pessoais são carregados - o "both" indica que o processo de carregamento é iniado independentemente do resultado do teste.

Quando todos os processos de carregamento são concluídos, uma função é executada, no caso 'MyApp.init'.

Pessoalmente, prefiro esse modo de carregamento de script assíncrono. E como confio nos testes de recursos fornecidos pela modernizr ao criar um site, eu o incluo no site de qualquer maneira. Portanto, não há realmente sobrecarga.

Emanuel Kluge
fonte
2
Acho que você está perdendo o objetivo da pergunta - como você carregaria o script moernizr de uma CDN?
precisa saber é o seguinte
2
Não recomendo carregar o Modernizr a partir de uma CDN. Deve-se obter a menor compilação personalizada do modernizr.com.
Emanuel Kluge
2
Portanto, esta opção recebe +16, em comparação com os 500/200 + que as outras opções estão recebendo. Mas isso parece muito bom. Simplesmente não é popular devido a depender do Modernizer? De qualquer maneira, eu uso o Modernizer em nosso site. Portanto, se isso for melhor do que as outras respostas, alguém pode me avisar? Sou bastante novo no JQuery, portanto, o esclarecimento é apreciado.
redfox05
2
Esta foi uma opção muito boa no momento da resposta, mas a partir de 2015, yepnope.jsestá obsoleta. Veja stackoverflow.com/questions/33986561/…
Obmerk Kronen
Modernizr foi criado para resolver problemas como esta pergunta. +1
Carlos Quijano
21

Existem algumas ótimas soluções aqui, mas gostaria de dar um passo adiante em relação ao arquivo local.

Em um cenário em que o Google falha, ele deve carregar uma fonte local, mas talvez um arquivo físico no servidor não seja necessariamente a melhor opção. Eu trago isso à tona porque, no momento, estou implementando a mesma solução, apenas desejo retornar a um arquivo local que é gerado por uma fonte de dados.

Minhas razões para isso é que eu quero ter um pouco de mente quando se trata de acompanhar o que eu carrego do Google versus o que eu tenho no servidor local. Se eu quiser alterar as versões, manterá minha cópia local sincronizada com o que estou tentando carregar do Google. Em um ambiente em que há muitos desenvolvedores, acho que a melhor abordagem seria automatizar esse processo, para que tudo o que você precise fazer seja alterar um número de versão em um arquivo de configuração.

Aqui está a minha solução proposta que deve funcionar em teoria:

  • Em um arquivo de configuração de aplicativo, armazenarei três itens: URL absoluto da biblioteca, URL da API JavaScript e número da versão
  • Escreva uma classe que obtém o conteúdo do arquivo da própria biblioteca (obtém o URL da configuração do aplicativo), armazena-o na minha fonte de dados com o nome e o número da versão
  • Escreva um manipulador que retire meu arquivo local do banco de dados e armazene em cache o arquivo até que o número da versão seja alterado.
  • Se ele mudar (na configuração do meu aplicativo), minha classe extrairá o conteúdo do arquivo com base no número da versão, salvará como um novo registro na minha fonte de dados e o manipulador entrará em ação e exibirá a nova versão.

Em teoria, se meu código for escrito corretamente, tudo o que preciso fazer é alterar o número da versão na configuração do meu aplicativo e, em seguida, o viola! Você tem uma solução de fallback automatizada e não precisa manter arquivos físicos em seu servidor.

O que todos pensam? Talvez isso seja um exagero, mas poderia ser um método elegante de manter suas bibliotecas AJAX.

Bolota

Bolota
fonte
Se você está fazendo todo esse trabalho apenas para jQuery, diria que é um exagero. No entanto, se você já possui alguns desses componentes para outras partes do seu aplicativo (por exemplo, se você já carrega scripts de um banco de dados), isso parecerá muito bom.
Michael Haren
1
+1 por ser completo e inovador, embora não esteja convencido de que o benefício justifique o tempo e a complexidade do desenvolvedor.
Cory Casa
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);

}

Depois de tentar incluir a cópia do Google na CDN.

No HTML5, você não precisa definir o typeatributo.

Você também pode usar...

window.jQuery || document.write('<script src="/libs/jquery.js"><\/script>');
alex
fonte
2
+1 parece mais limpo. há um erro de digitação menor no topo que eu não posso limpar desde a sua menor ery dois suportes de fechamento após 'indefinido'
Naveen
1
A primeira opção evita o aviso do Chrome[Violation] Avoid using document.write().
Bob Stein
A primeira opção, infelizmente, não parece carregar de forma síncrona . Segunda opção faz .
Bob Stein
10

Você pode usar seu arquivo local como último recurso.

Parece que agora o CDN do jQuery não suporta https. Se o fez, você pode querer carregar a partir daí primeiro.

Então, aqui está a sequência: Google CDN => Microsoft CDN => Sua cópia local.

<!-- 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
fonte
Existe realmente a necessidade de mais de um substituto? se ambos estiverem usuário off-line estará esperando por mais de um minuto antes de ver o seu site
George Filippakos
1
Não leva 1 minuto para um script falhar ao carregar, é preciso.
Edward Olamisan
@ geo1701 e Edward, realmente não há necessidade de um terceiro. Mesmo um fallback ainda não foi comprovado como confiável. Se a API do Google estiver inativa, ainda não recebi nenhuma garantia de que a primeira tentativa falhará. Eu experimentei um cenário onde um CDN nunca deixou de carga, mantendo a página de nunca renderização, como mencionado aqui: stevesouders.com/blog/2013/03/18/http-archive-jquery/...
hexalys
6

Carregue condicionalmente a versão mais recente / herdada do jQuery e fallback:

<!--[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
fonte
Isso não é compatível com vários navegadores.
21717 Josh Habdas
Josh, sim, é.
Neiker
4

Aqui está uma ótima explicação sobre isso!

Também implementa atrasos no carregamento e tempos limite!

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

Stuart.Sklinar
fonte
As respostas somente de link não são úteis e são consideradas de baixa qualidade. Considere copiar os bits relevantes em sua resposta, com a atribuição, é claro, à fonte.
Random_user_name
@cale_b Você está brincando? Esta resposta tem mais de 7 anos, portanto, esse comentário é injustificado.
Stuart.Sklinar
Sim, é uma resposta antiga. Embora sua sugestão seja válida. Respostas que são meramente links em outros lugares são candidatos à exclusão. Leitor adicional: meta.stackoverflow.com/q/8259
Rob
Eu concordo totalmente, eu moderaria com sugestões - mas é inútil dizer isso 7 anos depois. Deveria ter sido moderado assim 7 anos atrás, não 7 anos depois.
Stuart.Sklinar
1
@ Stuart.Sklinar - se eu tivesse visto isso há 7 anos, eu teria :) Eu me encontrei aqui fazendo algumas pesquisas e vendo isso pela primeira vez. Desculpe a frustrá-lo - Eu acho que o nosso trabalho no SO devem ser administradores do site, que às vezes significa comentar, editar ou melhorar velhas perguntas ou respostas ...
random_user_name
4

Para as pessoas que usam o ASP.NET MVC 5, adicione esse código no seu BundleConfig.cs para ativar a CDN para 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
fonte
4

ATUALIZAÇÃO:
Esta resposta acabou errada. Por favor, veja os comentários para a explicação real.


A maioria de vocês já foi respondida, mas quanto à parte final:

Qual seria o perigo das duas cópias aparecerem?

Nenhum realmente. Você desperdiçaria largura de banda, pode adicionar alguns milissegundos ao fazer o download de uma segunda cópia inútil, mas não há nenhum dano real se os dois aparecerem. Obviamente, você deve evitar isso usando as técnicas mencionadas acima.

WhyNotHugo
fonte
5
Na verdade, carregar o jQuery duas vezes pode causar muitos problemas, de acordo com esta pergunta .
ShadowCat7
por que você não o testou e carregou manualmente a biblioteca jquery duas vezes. então a resposta será revelada.
275156 Lukas_Mclachlan
Por que exatamente isso é tão errado? @ ShadowCat7, você pode ser mais específico sobre os problemas que isso causa? O único problema que vejo explicitamente identificado na pergunta que você vinculou é "limpar todos os plugins carregados anteriormente". Mas isso não se aplica ao carregamento do mesmo arquivo jQuery duas vezes consecutivas, certo? Eu pergunto porque as outras soluções aqui para o fallback local são muito complicadas e document.write é difamado como maligno em alguns lugares .
Bob Stein
2

Eu criei um Gist que deveria carregar dinamicamente o jQuery, se já não estiver carregado, e se a fonte falhar, ele continuará em fallbacks (costurados a partir de muitas respostas): https://gist.github.com/tigerhawkvok/9673154

Observe que pretendo manter o Gist atualizado, mas não esta resposta, pelo que vale a pena!

/* 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
fonte
2

JQuery hospedado pelo Google

  • Se você se preocupa com navegadores mais antigos, principalmente versões do IE anteriores ao IE9, esta é a versão do jQuery mais amplamente compatível.
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
  • Se você não se importa com o oldIE, este é menor e mais rápido:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>

Plano de Backup / Fallback!

  • De qualquer forma, você deve usar um fallback para local apenas no caso de o CDN do Google falhar (improvável) ou ser bloqueado em um local de onde seus usuários acessam seu site (um pouco mais provável), como o Irã ou, às vezes, a China.
<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>

Referência: http://websitespeedoptimizations.com/ContentDeliveryNetworkPost.aspx

Ryan
fonte
Nota: o carregamento de scripts por protocolos inseguros abre um vetor de ataque XSS.
Josh Habdas
2

Considero que deve escapar do último <to \ x3C na string. Quando o navegador vê, considera que este é o fim do bloco de scripts (como o analisador HTML não tem idéia sobre JavaScript, ele não pode distinguir entre algo que apenas aparece em uma string e algo que realmente significa finalizar o script elemento). Portanto, aparecer literalmente em JavaScript que esteja dentro de uma página HTML (no melhor dos casos) causará erros e (no pior dos casos) será um enorme buraco na segurança.

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

Ou

if(!window.jQuery){

Não funcionará se a versão do cdn não estiver carregada, porque o navegador executará essa condição e, durante o processo, ainda fará o download do restante dos javascripts que precisam do jQuery e retornam erros. A solução foi carregar scripts através dessa condição.

    <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
fonte
Encontrei um problema ao testar scripts no Google Chrome - cache. Portanto, para testes locais, substitua src na seção else por algo como s.src = 'my_javascripts.js' + '?' + Math.floor (Math.random () * 10001);
Mirek Komárek
A resposta de Alex não funcionará se a versão do cdn não for carregada, porque o navegador funcionará com essa condição e durante o download do restante dos javascripts que precisam de jquery e retorna erro -> arquivos JavaScript sendo baixados impedirão a execução do próximo trecho de código então não é um problema .
19411 alex
2

Quase todas as CDNs públicas são bastante confiáveis. No entanto, se você estiver preocupado com o domínio do Google bloqueado, poderá simplesmente recorrer a uma CDN jQuery alternativa . No entanto, nesse caso, você pode preferir fazer o contrário e usar outra CDN como sua opção preferida e usar o CDN do Google para evitar solicitações com falha e tempo de espera:

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

Usando a sintaxe Razor no ASP.NET, esse código fornece suporte a fallback e funciona com uma raiz 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>

Ou faça um ajudante ( visão geral do ajudante ):

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

e use-o assim:

@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
fonte
Eu nunca coração sobre Navalha, mas parece que um ofuscador, exceto que torna o código mais longo em vez de mais curto (é o dobro do tempo como este .
maaartinus
@ maaartinus: Essa não é uma comparação de maçãs com maçãs. A resposta de BenjaminRH, à qual você se refere, é para um único script hospedado pela CDN. Com o CdnScriptauxiliar, você precisa de apenas uma linha de código por script . Quanto mais scripts você tiver, maior será o retorno.
Edward Brey 17/05
Claro ... foi apenas um discurso retórico. No entanto, acho que não é o caminho ideal. Se algo falhar, eu ignorarei completamente a CDN e mudarei para o fallback de todos os scripts. Não tenho certeza se isso é possível, pois não sei exatamente como o carregamento funciona.
Maaartinus 17/05
@maaartinus: Como cada carregamento de script da CDN pode falhar independentemente, você deve verificar cada carregamento separadamente. Não há método confiável para uma única verificação da CDN, seguida pelo carregamento de todos os scripts da CDN vs. localmente.
Edward Brey 17/05
O caso que me preocupa é uma falha do site da CDN, levando a tempos de espera para muitas cargas. Então, eu gostaria de ter algo parecido try { for (Script s : ...) cdnLoad(s); } catch (...) { for (Script s : ...) ownLoad(s); }. Traduzir isso para um monte de ifs pode ser um pesadelo.
Maaartinus 17/05
1

Embora a escrita document.write("<script></script>")pareça mais fácil para o backoff do jQuery, o Chrome fornece um erro de validação nesse caso. Então eu prefiro quebrar a palavra "script". Portanto, fica mais seguro como acima.

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

Para problemas de longo prazo, seria melhor registrar os fallbacks do JQuery. No código acima, se o primeiro CDN não estiver disponível, o JQuery será carregado a partir de outro CDN. Mas você pode querer saber esse CDN incorreto e removê-lo permanentemente. (este caso é um caso muito excepcional) Também é melhor registrar problemas de fallback. Assim, você pode enviar casos errados com o AJAX. Como o JQuery não está definido, você deve usar vanilla javascript para solicitação 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
fonte
0

Mais um substituto que substitui ajax.googleapis.com por 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);
  • Você pode manter uma versão do jQuery especificando-a na string
  • Perfeito para gerenciamento de ativos que não funciona com snips HTML
  • Testado na natureza - funciona perfeitamente para usuários da China
redaxmedia
fonte
Você poderia elaborar a seguinte declaração: "Você não precisa se preocupar com a versão do jQuery"?
21417 Josh Habdas #
A versão é parte do URL que não é goint de ser tocado por esta abordagem ... jQuery / 3.xx / jquery.min.js
redaxmedia
1
Isso pode causar falhas quando o jQuery reverter para a versão 4 e introduzir alterações incompatíveis com versões anteriores?
Josh Habdas
-1, porque isso causará quebra se o jQuery introduzir alterações de quebra que seus scripts ainda não suportarão, a menos que a versão seja especificada.
Lookaji
@lookaji Acho que você não entende o fallback. Ele substitui o domínio em que está hospedado e NÃO toca no nome do arquivo / versão.
Redaxmedia #
0

Você pode usar código como:

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

Mas também existem bibliotecas que você pode usar para configurar vários possíveis fallbacks para seus scripts e otimizar o processo de carregamento:

  • basket.js
  • RequireJS
  • yepnope

Exemplos:

basket.js Eu acho que a melhor variante por enquanto. Armazenará em cache seu script no localStorage, o que acelerará os próximos carregamentos. A chamada mais simples:

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

Isso retornará uma promessa e você poderá fazer a próxima chamada com erro ou carregar dependências com êxito:

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