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?


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


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.


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

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.


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


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.


3
$(document).ready(handler)é mais legível do $(handler)que o recomendado ...
— gdoron está apoiando Monica
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.