Por que “$ (). Ready (handler)” não é recomendado?

88

Do site de documentos da API jQuery paraready

Todas as três sintaxes a seguir são equivalentes:

  • $ (documento) .ready (manipulador)
  • $ (). ready (handler) (isso não é recomendado)
  • $ (manipulador)

Depois de fazer o dever de casa - ler e brincar com o código-fonte , não tenho ideia do por que

$().ready(handler) 

não é recomendado. A primeira e a terceira maneiras são exatamente as mesmas, a terceira opção chama a função pronta em um objeto jQuery em cache com document:

rootjQuery = jQuery(document);
...
...

// HANDLE: $(function)
// Shortcut for document ready
} else if ( jQuery.isFunction( selector ) ) {
    return rootjQuery.ready( selector );
}

Mas a função pronta não tem interação com o seletor dos elementos de nó selecionados, o readycódigo-fonte:

ready: function( fn ) {
    // Attach the listeners
    jQuery.bindReady();
        // Add the callback
    readyList.add( fn );
        return this;
},

Como você pode ver, ele apenas adiciona o retorno de chamada a uma fila interna ( readyList) e não altera ou usa os elementos do conjunto. Isso permite que você chame a readyfunção em cada objeto jQuery.

Gostar:

  • seletor regular : $('a').ready(handler) DEMO
  • Seletor sem sentido : $('fdhjhjkdafdsjkjriohfjdnfj').ready(handler) DEMO
  • Seletor indefinido : $().ready(handler) DEMO

Finalmente ... à minha pergunta: Por que $().ready(handler)não é recomendado?

gdoron está apoiando Monica
fonte
60
@ChaosPandion: Para mim, parece que ele se esforça para entender as ferramentas que usa, como a palma da mão. Eu não chamaria exatamente isso de esforço desperdiçado.
Jon
5
Boa pergunta. Se alguém estiver interessado, aqui está uma comparação de desempenho ... que mostra (pelo menos no Chrome) que a versão "não recomendada" é realmente a mais rápida.
James Allardice
5
Uma pergunta melhor é por que eles existem, deve ser um método estático ( $.readypor exemplo) e não requer a construção de um objeto jQuery em primeiro lugar.
Esailija
2
@Esailija mostra o melhor de todos. A menos que o jQuery planeje fornecer algum tipo de .ready()capacidade para elementos individuais, não deve haver razão para construir um objeto jQuery.
2
@ChaosPandion. Você não pode usar isso ... $.readyjá é usado por uma função jQuery interna, procure o código-fonte ready:.
gdoron está apoiando Monica

Respostas:

88

Recebi uma resposta oficial de um dos desenvolvedores jQuery:

$().ready(fn)só funciona porque $()costumava ser um atalho para $(document) (jQuery <1.4)
Então $().ready(fn)era um código legível.

Mas as pessoas costumavam fazer coisas assim $().mouseover()e todo tipo de loucura.
e as pessoas tiveram que fazer $([])para obter um objeto jQuery vazio

Então, em 1.4 nós o mudamos para $()dar um jQuery vazio e nós apenas $().ready(fn)trabalhamos para não quebrar muito código

$().ready(fn) agora é literalmente apenas corrigido no núcleo para fazê-lo funcionar corretamente para o caso legado.

O melhor lugar para a readyfunção é $.ready(fn), mas é uma decisão de design muito antiga e é isso que temos agora.


Eu perguntei a ele:

Você acha que $ (fn) é mais legível do que $ (). Ready (fn)?!

Sua resposta foi:

Eu sempre faço $ (document) .ready (fn) em aplicativos reais e normalmente há apenas um bloco pronto para doc no aplicativo, não é exatamente como uma coisa de manutenção.

Acho que $ (fn) também é bastante ilegível , é apenas algo que você precisa saber que funciona ™ ...

gdoron está apoiando Monica
fonte
1
Faz sentido, jQuery
leva
@Esailija: Se eles fossem tão sérios, eles não teriam mudado o comportamento $()em primeiro lugar (por mais bobo que esse comportamento possa ter sido) . Por outro lado, você está certo. Eles nem sempre estão inclinados a fazer alterações significativas, como foi mostrado quando tentaram alterar e .attr(), em seguida, fizeram uma reversão rápida alguns dias depois. Isso os vinculou a algumas de suas infelizes decisões de design no início (e na meia-idade).
3
@gdoron +1 por tirá-lo direto da boca do cavalo.
2
@gdoron +1 por obter a resposta real. E, sim, estivemos muito próximos em nossas percepções.
VisioN
" é apenas uma coisa que você precisa saber que funciona ™ ..." Bem, $(selector[, context])e também $(html[, ownerDocument]). Na verdade, você também pode usar, em jQuery()vez de $()se o problema for ter que saber que funciona. Ou por que usar o jQuery?
JAB de
11

Uma vez que as diferentes opções fazem praticamente a mesma coisa que você apontou, é hora de colocar o chapéu do escritor da biblioteca e fazer algumas suposições.

  1. Talvez o pessoal da jQuery gostaria de ter $()disponível para uso futuro (duvidoso, pois $().readyestá documentado para funcionar, mesmo que não seja recomendado; também poluiria a semântica de $se fosse especial).

  2. Um motivo muito mais prático: a segunda versão é a única que não acaba embrulhando document, por isso é mais fácil quebrá-la na manutenção do código. Exemplo:

    // BEFORE
    $(document).ready(foo);
    
    // AFTER: works
    $(document).ready(foo).on("click", "a", function() {});

    Compare isso com

    // BEFORE
    $().ready(foo);
    
    // AFTER: breaks
    $().ready(foo).on("click", "a", function() {});
  3. Relacionado ao acima: readyé uma aberração no sentido de que é (o único?) Método que funcionará da mesma forma, não importa o que o objeto jQuery envolve (mesmo que não envolva nada como é o caso aqui). Esta é uma grande diferença da semântica de outros métodos jQuery, portanto, confiar especificamente nisso é corretamente desencorajado.

    Atualização: Como o comentário de Esailija aponta, de uma perspectiva de engenharia readydeveria realmente ser um método estático exatamente porque funciona assim.

Atualização # 2: Explorando a fonte, parece que em algum ponto no branch 1.4 $()foi alterado para corresponder $([]), enquanto no 1.3 ele se comportou como $(document). Essa mudança reforçaria as justificativas acima.

Jon
fonte
Eu nunca tinha visto um código como este, o antigo idioma era$(document).ready( function(){ //your code here } );
Esailija
Não entendi a segunda atualização, você pode elaborar mais um pouco, por favor? Procurei por versões mais antigas, mas não consegui encontrar nenhuma diferença para este problema de objeto jQuery vazio.
gdoron está apoiando Monica
@gdoron: Quero dizer, a mudança de selector = selector || documentpara if(!selector) return this.
Jon
4

Eu diria que é simplesmente o fato de que $()retorna um objeto vazio, ao passo $(document)que não o faz sua aplicação ready()a coisas diferentes; ainda funciona, mas eu diria que não é intuitivo.

$(document).ready(function(){}).prop("title") // the title
$().ready(function(){}).prop("title")  //null - no backing document
Alex K.
fonte
1
Sim, as mesmas percepções estão nesta resposta . Portanto, as mudanças ocorreram na versão 1.4, que lançou uma nova política de devolução.
VisioN
Eu nunca vi alguém alterando o título do documento enquanto anexava um retorno de chamada pronto, e você pode simplesmente fazer isso com vanilla js sem jQuery . Não digo que não seja a resposta, mas não é um bom motivo.
gdoron está apoiando Monica
Bem, nenhuma propriedade ou método de documento pode ser encadeado via$()
Alex K.
2
@AlexK. o que ele queria dizer era que ninguém na verdade acorrenta atrás .readyporque é um idioma bem estabelecido não fazer isso. Claro, há uma chance teórica de alguém fazer isso, mas nunca vi um código fazendo isso (o que não é um bom argumento, mas você sabe: D).
Esailija
2
Talvez por causa desse acaso teórico o método não seja recomendado , já que tem comportamento diferente em lançamentos diferentes.
VisioN
3

Mais do que provavelmente, este é apenas um bug de documentação e deve ser corrigido, a única desvantagem de usar $().ready(handler)é a sua legibilidade. Claro, argumente que isso $(handler)é igualmente ilegível. Eu concordo, é por isso que não uso .

Você também pode argumentar que um método é mais rápido do que outro. No entanto, com que frequência você chama esse método vezes suficientes em uma linha em uma única página para notar a diferença?

Em última análise, tudo se resume à preferência pessoal. Não há nenhuma desvantagem em usar $().ready(handler)outro argumento além da legibilidade. Eu acho que a documentação está levando mal neste caso.

Kevin B
fonte
+1! Você estava absolutamente certo! Você vai adorar ler a resposta oficial do jQuery. Eu adicionei como uma resposta.
gdoron está apoiando Monica
2

Só para deixar óbvio que há alguma inconsistência nos três, acrescentei a quarta forma frequentemente usada: (function($) {}(jQuery));

Com esta marcação:

<div >one</div>
<div>two</div>
<div id='t'/>

e este código:

var howmanyEmpty = $().ready().find('*').length;
var howmanyHandler = $(function() {}).find('*').length;
var howmanyDoc = $(document).ready().find('*').length;
var howmanyPassed = (function($) { return $('*').length; }(jQuery));
var howmanyYuck = (function($) {}(jQuery));
var howmanyYuckType = (typeof howmanyYuck);

$(document).ready(function() {
    $('#t').text(howmanyEmpty + ":" + howmanyHandler + ":" 
        + howmanyDoc + ":" + howmanyPassed + ":" + howmanyYuckType);
});

Os resultados exibidos do div da última instrução são: 0: 9: 9: 9: indefinido

SO, apenas as versões Handler e Doc são consistentes com a convenção jQuery de retornar algo útil conforme eles obtêm o seletor de documentos e com o formulário Aprovado você deve retornar algo (eu não faria isso, eu acho, mas coloque apenas para mostrar "por dentro" tem algo).

Aqui está uma versão violenta disso para os curiosos: http://jsfiddle.net/az85G/

Mark Schultheiss
fonte
Não consigo ver qual é o problema de não encontrar nada, o contexto que você deu para o jQuery é nullentão .find('*').lengthretorne 0 . Você acha algo ruim com esse comportamento (óbvio)?
gdoron está apoiando Monica
@gdoron - Não encontrei nada de ruim com esse comportamento, só queria apontar a diferença em relação a quando TEM um seletor que NÃO é nulo - observe que esse seletor vazio é provavelmente o motivo dos comentários "mais rápidos" serem anotados em outro lugar, pois tem um objeto menor para processar, mas retorna um objeto e não "indefinido" nessa instância. Eu realmente gosto da pergunta e votei positivamente :)
Mark Schultheiss
A razão é porque é mais rápido porque a primeira condição de "quebra" do ctor é if(!selector) return thisse você der algo mais, há regexe outras coisas acontecendo ... Obrigado por palavras gentis ... Acho que posso pedir à equipe jQuery para responda isso (inferno, não é minha biblioteca :-)).
gdoron está apoiando Monica
Sim, eu não estudei essa parte específica da base de código, eu hackeei o núcleo para colocar correções internas para bugs, mas não essa parte. Eu prefiro ver o jQuery(document).ready(function(){});formulário em nossa base de código no momento, pois há diferentes níveis de experiência em jQuery e é "mais óbvio" para as pessoas novas que é uma função de manipulador de eventos para jQuery.
Mark Schultheiss
0

Acho que isso é mais para facilitar a leitura do que qualquer outra coisa.

Este não é tão expressivo

$().ready(handler);

Como

$(document).ready(handler)

Talvez eles estejam tentando promover alguma forma de jQuery idiomática.

Hyangelo
fonte
3
$(document).ready(handler)é mais legível do $(handler)que o recomendado ...
gdoron está apoiando Monica