Perché "$ (). Ready (handler)" non è consigliato?


88

Dal sito della documentazione dell'API jQuery perready

Tutte e tre le seguenti sintassi sono equivalenti:

  • $ (documento) .ready (gestore)
  • $ (). ready (gestore) (non consigliato)
  • $ (gestore)

Dopo aver fatto i compiti - leggere e giocare con il codice sorgente , non ho idea del perché

$().ready(handler) 

non è consigliato. Il primo e il terzo modo sono esattamente gli stessi, la terza opzione chiama la funzione ready su un oggetto jQuery memorizzato nella cache con document:

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

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

Ma la funzione ready non ha alcuna interazione con il selettore degli elementi del nodo selezionato, Il readycodice sorgente:

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

Come puoi vedere, aggiunge semplicemente il callback a una coda interna ( readyList) e non cambia o utilizza gli elementi nel set. Ciò consente di chiamare la readyfunzione su ogni oggetto jQuery.

Piace:

  • selettore regolare : $('a').ready(handler) DEMO
  • Selettore di sciocchezze : $('fdhjhjkdafdsjkjriohfjdnfj').ready(handler) DEMO
  • Selettore non definito : $().ready(handler) DEMO

Infine ... alla mia domanda: perché $().ready(handler)non è consigliato?


60
@ ChaosPandion: A me sembra che si sforzi di capire gli strumenti che usa come il palmo della sua mano. Non chiamerei esattamente quello sforzo sprecato.
Jon

5
Buona domanda. Se qualcuno è interessato, ecco un confronto delle prestazioni ... che mostra (almeno in Chrome) che la versione "non consigliata" è in realtà la più veloce.
James Allardice

5
Una domanda migliore è perché esistono anche questi, dovrebbe essere un metodo statico ( $.readyad esempio) e non richiedere la costruzione di un oggetto jQuery in primo luogo.
Esailija

2
@Esailija fa il punto migliore di tutti. A meno che jQuery non preveda di fornire una sorta di .ready()funzionalità per i singoli elementi, non dovrebbe esserci alcun motivo per costruire un oggetto jQuery.

2
@ChaosPandion. Non puoi usarlo ... $.readyè già preso da una funzione jQuery interna, cerca nel codice sorgente ready:.
gdoron sostiene Monica

Risposte:


88

Ho ricevuto una risposta ufficiale da uno degli sviluppatori jQuery:

$().ready(fn)funziona solo perché $()era una scorciatoia per $(document) (jQuery <1.4)
Quindi $().ready(fn)era un codice leggibile.

Ma le persone erano solite fare cose del genere $().mouseover()e ogni sorta di altra follia.
e le persone dovevano fare $([])per ottenere un oggetto jQuery vuoto

Quindi in 1.4 l'abbiamo cambiato in modo da $()dare un jQuery vuoto e abbiamo appena fatto $().ready(fn)funzionare in modo da non rompere un sacco di codice

$().ready(fn) è letteralmente ora solo patchato nel core per farlo funzionare correttamente per il caso legacy.

Il posto migliore per la readyfunzione è $.ready(fn), ma è una decisione di design davvero vecchia ed è quello che abbiamo ora.


Gli ho chiesto:

Pensi che $ (fn) sia più leggibile di $ (). Ready (fn)?!

La sua risposta è stata:

Faccio sempre $ (document) .ready (fn) nelle app reali e in genere c'è solo un blocco pronto per i documenti nell'app non è esattamente come una cosa di manutenzione.

Penso che anche $ (fn) sia abbastanza illeggibile , è solo una cosa che devi sapere funziona ™ ...


1
Ha senso, jQuery è piuttosto serio riguardo alla compatibilità all'indietro
Esailija

@Esailija: Se fossero stati così seri, non avrebbero cambiato il comportamento di $()in primo luogo (per quanto sciocco possa essere stato quel comportamento) . D'altra parte, hai ragione. Non sono sempre così inclini ad apportare modifiche sostanziali, come è stato mostrato quando hanno provato a cambiare .attr(), quindi hanno fatto un rapido ripristino pochi giorni dopo. Questo li ha legati ad alcune delle loro sfortunate decisioni di progettazione iniziali (e di mezza età).

3
@gdoron +1 per averlo preso direttamente dalla bocca del cavallo.

2
@gdoron +1 per ottenere la vera risposta. E sì, siamo stati abbastanza vicini nelle nostre percezioni.
VisioN

" è solo una cosa che devi sapere funziona ™ ..." E così sono $(selector[, context])e $(html[, ownerDocument]). In effetti, potresti anche usarlo jQuery()invece di $()se il problema è il dover sapere che funziona. O perché usare addirittura jQuery?
JAB

11

Poiché le diverse opzioni fanno più o meno la stessa cosa che hai indicato, è ora di indossare il cappello da scrittore della biblioteca e fare alcune ipotesi.

  1. Forse le persone jQuery vorrebbero avere a $()disposizione per un uso futuro (dubbio dato che $().readyè documentato per funzionare, anche se non consigliato; inquinerebbe anche la semantica di casi $speciali).

  2. Un motivo molto più pratico: la seconda versione è l'unica che non finisce per avvolgere document, quindi è più facile rompere quando si mantiene il codice. Esempio:

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

    Confronta questo con

    // BEFORE
    $().ready(foo);
    
    // AFTER: breaks
    $().ready(foo).on("click", "a", function() {});
    
  3. In relazione a quanto sopra: readyè un mostro nel senso che è (l'unico?) Metodo che funzionerà allo stesso modo indipendentemente da ciò che l'oggetto jQuery avvolge (anche se non avvolge nulla come nel caso qui). Questa è una grande differenza rispetto alla semantica di altri metodi jQuery, quindi fare affidamento su questo è giustamente scoraggiato.

    Aggiornamento: come sottolinea il commento di Esailija, da un punto di vista ingegneristico readydovrebbe davvero essere un metodo statico proprio perché funziona in questo modo.

Aggiornamento # 2: Scavando alla fonte, sembra che ad un certo punto nel ramo 1.4 sia $()stato cambiato per abbinarlo $([]), mentre in 1.3 si è comportato come $(document). Questa modifica rafforzerebbe le giustificazioni di cui sopra.


Non ho mai visto un codice come questo, però, il vecchio idioma era$(document).ready( function(){ //your code here } );
Esailija

Non sono riuscito a capire il secondo aggiornamento, puoi approfondire ancora per favore? Ho cercato versioni precedenti, ma non sono riuscito a trovare alcuna differenza per questo problema di oggetto jQuery vuoto.
gdoron supporta Monica

@gdoron: intendo il passaggio da selector = selector || documenta if(!selector) return this.
Jon

4

Direi che è semplicemente il fatto che $()restituisce un oggetto vuoto mentre $(document)non lo fa per l'applicazione ready()a cose diverse; funziona ancora, ma direi che non è intuitivo.

$(document).ready(function(){}).prop("title") // the title
$().ready(function(){}).prop("title")  //null - no backing document

1
Sì, le stesse percezioni sono in questa risposta . Quindi le modifiche sono avvenute nella versione 1.4, che ha rilasciato una nuova politica di restituzione.
VisioN

Non ho mai visto qualcuno cambiare il titolo del documento mentre allega la richiamata pronta, e puoi semplicemente farlo con vanilla js senza jQuery . Non dico che potrebbe non essere la risposta, ma non è una buona ragione.
gdoron supporta Monica

Beh, nessuna proprietà o metodo del documento può essere concatenato tramite$()
Alex K.

2
@AlexK. il suo punto era che nessuno in realtà si incatena .readyperché è un idioma ben consolidato non farlo. Sicuramente c'è una possibilità teorica che qualcuno lo faccia, ma non ho mai visto del codice farlo (il che non è un buon argomento ma sai: D).
Esailija

2
Forse a causa di questo metodo casuale teorico non è raccomandato , poiché ha un comportamento diverso in diverse versioni.
VisioN

3

Molto probabilmente questo è solo un bug della documentazione e dovrebbe essere corretto, l'unico svantaggio dell'utilizzo $().ready(handler)è la sua leggibilità. Certo, sostiene che $(handler)è altrettanto illeggibile. Sono d'accordo, ecco perché non lo uso .

Puoi anche sostenere che un metodo è più veloce di un altro. Tuttavia, quante volte chiami questo metodo abbastanza volte di seguito su una singola pagina per notare una differenza?

Alla fine si tratta di preferenze personali. Non ci sono svantaggi nell'usare un $().ready(handler)argomento diverso da quello della leggibilità. Penso che in questo caso la documentazione sia mancante.


+1! Avevi assolutamente ragione! Ti piacerà leggere la risposta ufficiale di jQuery. L'ho aggiunto come risposta.
gdoron sostiene Monica

2

Solo per rendere palesemente ovvio che c'è qualche incongruenza nei tre, in più ho aggiunto la quarta forma spesso usata: (function($) {}(jQuery));

Con questo markup:

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

e questo codice:

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

I risultati visualizzati del div dall'ultima istruzione sono: 0: 9: 9: 9: undefined

COSÌ, solo le versioni Handler e Doc sono coerenti con la convenzione jQuery di restituire qualcosa di utile poiché ottengono il selettore di documenti e con il modulo Passed devi restituire qualcosa (non lo farei, penserei, ma inseriscilo per mostrare "dentro" che ha qualcosa).

Ecco una versione violina di questo per i curiosi: http://jsfiddle.net/az85G/


Non riesco a vedere qual è il problema con il fatto che non trova nulla, il contesto che hai fornito per jQuery è nullquindi .find('*').lengthrestituisci 0 . Trovi qualcosa di brutto in questo (ovvio) comportamento?
gdoron supporta Monica

@gdoron - Non trovo niente di male in questo comportamento, volevo solo sottolineare la differenza rispetto a quando ha un selettore che NON è nullo - nota che questo selettore vuoto è probabilmente il motivo per cui vengono annotati i commenti "più veloci" altrove poiché ha un oggetto più piccolo da elaborare, ma restituisce un oggetto e non "undefined" in quell'istanza. Mi piace molto la domanda e l'ho votata positivamente :)
Mark Schultheiss

Il motivo è perché è più veloce è, perché la prima condizione di "interruzione" del ctor è if(!selector) return thisse dai qualcos'altro, ci sono regexe altre cose in corso ... Grazie per le parole gentili ... Penso che potrei chiedere al team di jQuery di rispondi a questa domanda (diavolo, non è la mia libreria :-)).
gdoron sostiene Monica

Sì, non ho studiato questa particolare parte del codice di base, ho hackerato il core per inserire correzioni interum per i bug ma non quella parte di esso. Preferisco vedere il jQuery(document).ready(function(){});modulo nella nostra base di codice al momento in quanto vi sono diversi livelli di competenza in jQuery ed è "più ovvio" per le nuove persone che è una funzione di gestore di eventi per jQuery.
Mark Schultheiss

0

Penso che questo sia davvero più per la leggibilità che per qualsiasi altra cosa.

Questo non è così espressivo

$().ready(handler);

come

$(document).ready(handler)

Forse stanno cercando di promuovere una qualche forma di jQuery idiomatica.


3
$(document).ready(handler)è più leggibile di quello $(handler)consigliato ...
gdoron supporta Monica
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.