online - jquery html5




A melhor maneira de usar o jQuery hospedado do Google, mas voltar para minha biblioteca hospedada no Google falha (15)

A incapacidade de carregar o recurso de um armazenamento de dados externo além do seu controle é difícil. Procurar por funções perdidas é totalmente falacioso, como um meio de evitar sofrer um tempo limite, conforme descrito aqui: http://www.tech-101.com/support/topic/4499-issues-using-a-cdn/

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

Eu 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 de ambas as cópias passarem?

Não está realmente à procura de respostas como "use o Google" ou "use apenas o seu". Eu entendo esses argumentos. Também entendo que o usuário provavelmente terá a versão do Google armazenada em cache. Estou pensando em fallbacks para a nuvem em geral.

Edit: Esta parte adicionada ...

Como o Google sugere o uso do google.load para carregar as bibliotecas do ajax e ele executa um retorno de chamada quando feito, estou pensando se essa é a chave para serializar esse problema.

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

Atualização: jQuery agora hospedado no CDN da Microsoft.

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


A maneira mais fácil e mais 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>


Carregar condicionalmente a versão e o fallback do latest / legacy jQuery:

<!--[if lt IE 9]>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
    <script>window.jQuery || document.write('<script src="/public/vendor/jquery-legacy/dist/jquery.min.js">\x3C/script>')</script>
<![endif]-->
<!--[if gte IE 9]><!-->
    <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
    <script>window.jQuery || document.write('<script src="/public/vendor/jquery/dist/jquery.min.js">\x3C/script>')</script>
<!--<![endif]-->

Eu considero que deve escapar do último <to \ x3C na string. Quando o navegador vê, ele considera que este é o fim do bloco de script (já que o analisador de HTML não tem idéia sobre JavaScript, ele não consegue distinguir entre algo que aparece em uma string e algo que realmente significa terminar o script elemento). Assim, aparecer literalmente em JavaScript dentro de uma página HTML (na melhor das hipóteses) causará erros e (na pior das hipóteses) será uma grande falha de 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>

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

Por favor, note que eu 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();
}

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 objeto google que chama http://www.google.com/jsapi carregado no objeto da window . Se esse objeto não estiver presente, estamos assumindo que o acesso ao Google está falhando. Se esse for o caso, nós carregamos uma cópia local usando document.write . (Eu estou usando meu próprio servidor neste caso, por favor use o seu próprio para testar isso).

Eu também testo a presença de window.google.load - Eu também posso fazer um typeof verificação para ver se as coisas são objetos ou funções conforme apropriado. Mas eu acho que isso faz o truque.

Aqui está apenas a lógica de carregamento, já que o realce de código parece falhar, já que 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 isso for uma preocupação para os visitantes do seu site, você deve estar mexendo na API de bibliotecas AJAX do Google .

Curiosidade : eu tentei inicialmente usar um bloco try..catch para isso 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 ideia, puramente como um exercício.


Para as pessoas que usam a ASP.NET MVC 5, adicione este código em seu BundleConfig.cs para ativar o 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);

Se você tiver o modernizr.js embutido em seu site, poderá usar o yepnope.js integrado 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. Se não ("nope"), a versão local é carregada. Também seus scripts pessoais são carregados - o "ambos" indica que o processo de carregamento é iniated independentemente do resultado do teste.

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

Eu pessoalmente prefiro essa forma de carregamento de script assíncrono. E como eu confio nos testes de recursos fornecidos pelo modernizr ao construir um site, eu o tenho embutido no site de qualquer maneira. Então, na verdade, não há sobrecarga.


Usando a sintaxe do 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 usá-lo 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")

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

Parece que a partir de agora o próprio CDN do jQuery não suporta https. Se isso acontecesse, talvez você queira carregá-lo 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> 

ATUALIZAR:
Esta resposta acabou por estar errada. Por favor, veja os comentários para a explicação real.

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

Qual seria o perigo de ambas as cópias passarem?

Nenhum realmente. Você desperdiçaria largura de banda, poderia acrescentar alguns milissegundos fazendo o download de uma segunda cópia inútil, mas não haveria nenhum dano real se os dois passassem. Evidentemente, você deve evitar isso usando as técnicas mencionadas acima.


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 há bibliotecas que você pode usar para configurar vários fallbacks possíveis para seus scripts e otimizar o processo de carregamento:

  • basket.js
  • ExigirJS
  • yepnope

Exemplos:

basket.js Acho a melhor variante por enquanto. Armazenará seu script no localStorage, 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 em erro ou carregar dependências em caso de sucesso:

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

ExigirJS

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

if (typeof jQuery == 'undefined')) { ...

Ou

if(!window.jQuery){

Não funcionará se a versão do cdn não for carregada, porque o navegador executará essa condição e durante o download do restante dos javascripts que precisam do jQuery e retornará o erro. A solução foi carregar scripts por essa 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>





google-ajax-libraries