Dlaczego „$ (). Ready (handler)” nie jest zalecane?

88

Z witryny z dokumentacją jQuery API dlaready

Wszystkie trzy z następujących składni są równoważne:

  • $ (document) .ready (handler)
  • $ (). ready (handler) (nie jest to zalecane)
  • $ (handler)

Po odrabianiu lekcji - czytaniu i zabawie z kodem źródłowym nie mam pojęcia dlaczego

$().ready(handler) 

nie jest zalecane. Pierwszy i trzeci sposób są dokładnie takie same, trzecia opcja wywołuje funkcję ready na zbuforowanym obiekcie jQuery z document:

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

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

Ale gotowa funkcja nie ma interakcji z selektorem wybranych elementów węzła, readyKod źródłowy:

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

Jak widać, po prostu dodaje wywołanie zwrotne do wewnętrznej kolejki ( readyList) i nie zmienia ani nie używa elementów w zestawie. Pozwala to wywołać readyfunkcję na każdym obiekcie jQuery.

Lubić:

  • zwykły selektor: $('a').ready(handler) DEMO
  • Selektor bzdur : $('fdhjhjkdafdsjkjriohfjdnfj').ready(handler) DEMO
  • Niezdefiniowany selektor: $().ready(handler) DEMO

Wreszcie ... na moje pytanie: dlaczego $().ready(handler)nie jest zalecane?

gdoron wspiera Monikę
źródło
60
@ChaosPandion: Wydaje mi się, że stara się zrozumieć narzędzia, których używa, takie jak grzbiet dłoni. Nie nazwałbym tego zmarnowanym wysiłkiem.
Jon
5
Dobre pytanie. Jeśli ktoś jest zainteresowany, oto porównanie wydajności ... które pokazuje (przynajmniej w Chrome), że wersja „niezalecana” jest faktycznie najszybsza.
James Allardice,
5
Lepszym pytaniem jest, dlaczego w ogóle one istnieją, powinna to być metoda statyczna ( $.readyna przykład) i nie wymagać w pierwszej kolejności konstruowania obiektu jQuery.
Esailija,
2
@Esailija robi wszystko, co najlepsze. O ile jQuery nie planuje zapewnić jakichś .ready()możliwości dla poszczególnych elementów, nie powinno być powodu do konstruowania obiektu jQuery.
2
@ChaosPandion. Nie możesz tego użyć ... $.readyjest już zajęte przez wewnętrzną funkcję jQuery, wyszukaj kod źródłowy ready:.
gdoron wspiera Monikę

Odpowiedzi:

88

Otrzymałem oficjalną odpowiedź od jednego z programistów jQuery:

$().ready(fn)działa tylko dlatego, $()że był skrótem do $(document) (jQuery <1.4)
Więc $().ready(fn)był czytelny kod.

Ale ludzie robili takie rzeczy jak $().mouseover()i wszelkiego rodzaju inne szaleństwa.
i ludzie musieli zrobić, $([])aby uzyskać pusty obiekt jQuery

Więc w 1.4 zmieniliśmy to tak, że $()daje puste jQuery i po prostu wykonaliśmy $().ready(fn)pracę, aby nie zepsuć dużo kodu

$().ready(fn) jest teraz dosłownie załatany w jądrze, aby działał poprawnie w przypadku starszej wersji.

Najlepsze miejsce na tę readyfunkcję jest $.ready(fn), ale to naprawdę stara decyzja projektowa i to jest to, co mamy teraz.


Zapytałem go:

Czy uważasz, że $ (fn) jest bardziej czytelne niż $ (). Ready (fn) ?!

Jego odpowiedź brzmiała:

Zawsze robię $ (document) .ready (fn) w rzeczywistych aplikacjach i zazwyczaj w aplikacji jest tylko jeden blok gotowy na dokument, co nie jest dokładnie takie jak konserwacja.

Myślę, że $ (fn) też jest nieczytelny , to po prostu rzecz, o której musisz wiedzieć, że działa ™ ...

gdoron wspiera Monikę
źródło
1
To ma sens, jQuery poważnie podchodzi do wstecznej kompatybilności
Esailija,
@Esailija: Gdyby byli tak poważni, nie zmieniliby zachowania $()w pierwszej kolejności (tak głupkowate, jak mogło być to zachowanie) . Z drugiej strony masz rację. Nie zawsze są tak skłonni do dokonywania przełomowych zmian, jak pokazano, gdy próbowali to zmienić .attr(), a kilka dni później dokonali szybkiego powrotu. To wiąże ich z niektórymi z ich niefortunnych decyzji projektowych we wczesnym (i średnim wieku).
3
@gdoron +1 za wyciągnięcie go prosto z pyska konia.
2
@gdoron +1, aby uzyskać prawdziwą odpowiedź. I tak, w naszych wyobrażeniach byliśmy dość blisko.
VisioN
To tylko Rzecz, o której musisz wiedzieć, że działa ™…” Cóż, tak samo jest $(selector[, context])i $(html[, ownerDocument]). W rzeczywistości równie dobrze możesz po prostu użyć jQuery()zamiast, $()jeśli problemem jest wiedza, że ​​to działa. Albo po co w ogóle używać jQuery?
JAB,
11

Ponieważ różne opcje działają prawie tak samo, jak wskazałeś, nadszedł czas, aby założyć kapelusz pisarza bibliotecznego i zrobić kilka domysłów.

  1. Być może ludzie z jQuery chcieliby mieć $()dostęp do przyszłego użytku (wątpliwe, ponieważ $().readyudokumentowano, że działa, nawet jeśli nie jest to zalecane; zanieczyściłoby to również semantykę, $jeśli ma specjalne wielkości ).

  2. O wiele bardziej praktyczny powód: druga wersja jest jedyną, która nie kończy się zawijaniem document, więc łatwiej jest zepsuć podczas obsługi kodu. Przykład:

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

    Porównaj to z

    // BEFORE
    $().ready(foo);
    
    // AFTER: breaks
    $().ready(foo).on("click", "a", function() {});
    
  3. W związku z powyższym: readyjest dziwadłem w tym sensie, że jest to (jedyna?) Metoda, która będzie działać tak samo bez względu na to, co zawija obiekt jQuery (nawet jeśli nie zawija niczego, jak ma to miejsce w tym przypadku). Jest to zasadnicza różnica w stosunku do semantyki innych metod jQuery, więc szczególne poleganie na tym jest słusznie odradzane.

    Aktualizacja: Jak podkreśla komentarz Esailiji, z inżynieryjnego punktu widzenia readynaprawdę powinna to być metoda statyczna, dokładnie dlatego, że tak działa.

Aktualizacja # 2: Kopiąc u źródła, wydaje się, że w pewnym momencie gałąź 1.4 $()została zmieniona, aby pasowała $([]), podczas gdy w 1.3 zachowywała się podobnie $(document). Zmiana ta wzmocni powyższe uzasadnienia.

Jon
źródło
Nigdy jednak nie widziałem takiego kodu, stary idiom brzmiał$(document).ready( function(){ //your code here } );
Esailija
Nie mogłem zrozumieć drugiej aktualizacji, czy możesz rozwinąć trochę więcej? Szukałem starszych wersji, ale nie mogłem znaleźć żadnej różnicy dla tego problemu z pustym obiektem jQuery.
gdoron wspiera Monikę
@gdoron: Mam na myśli zmianę z selector = selector || documentna if(!selector) return this.
Jon
4

Powiedziałbym, że jest to po prostu fakt, że $()zwraca pusty obiekt, podczas gdy $(document)nie oznacza to, że stosujesz się ready()do różnych rzeczy; nadal działa, ale powiedziałbym, że nie jest intuicyjny.

$(document).ready(function(){}).prop("title") // the title
$().ready(function(){}).prop("title")  //null - no backing document
Alex K.
źródło
1
Tak, te same wyobrażenia są w tej odpowiedzi . Tak więc zmiany nastąpiły w wersji 1.4, która wydała nową politykę zwrotów.
VisioN
Nigdy nie widziałem, aby ktoś zmienił tytuł dokumentu podczas dołączania gotowego wywołania zwrotnego, a możesz to po prostu zrobić z vanilla js bez jQuery . Nie mówię, że to nie jest odpowiedź, ale to nie jest dobry powód.
gdoron wspiera Monikę
Cóż, żadne właściwości ani metody dokumentu nie mogą być łączone za pośrednictwem$()
Alex K.
2
@AlexK. Chodziło mu o to, że w rzeczywistości nikt tak naprawdę nie prowadzi łańcucha, .readyponieważ jest to dobrze ugruntowany idiom, którego nie wolno. Oczywiście, istnieje teoretyczna szansa, że ​​ktoś to zrobi, ale nigdy nie widziałem kodu, który to robi (co nie jest dobrym argumentem, ale wiesz: D).
Esailija,
2
Może z powodu tej teoretycznej szansy metoda nie jest zalecana , ponieważ ma różne zachowanie w różnych wersjach.
VisioN
3

Najprawdopodobniej jest to tylko błąd dokumentacji i powinien zostać naprawiony, jedyną wadą używania $().ready(handler)jest jego czytelność. Jasne, argumentuj, że $(handler)jest to równie nieczytelne. Zgadzam się, dlatego go nie używam .

Możesz również argumentować, że jedna metoda jest szybsza niż inna. Jednak jak często wywołujesz tę metodę wystarczająco dużo razy z rzędu na jednej stronie, aby zauważyć różnicę?

Ostatecznie sprowadza się to do osobistych preferencji. Nie ma żadnych wad używania $().ready(handler)innego argumentu niż argument czytelności. Myślę, że w tym przypadku dokumentacja jest chybiona.

Kevin B.
źródło
+1! Miałeś absolutną rację! Z przyjemnością przeczytasz oficjalną odpowiedź jQuery. Dodałem to jako odpowiedź.
gdoron wspiera Monikę
2

Aby było wyraźnie oczywiste, że w tych trzech jest pewna niespójność, dodałem też czwartą często używaną formę: (function($) {}(jQuery));

Z tym znacznikiem:

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

i ten kod:

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

Wyświetlane wyniki div z ostatniej instrukcji to: 0: 9: 9: 9: undefined

WIĘC, tylko wersje Handler i Doc są zgodne z konwencją jQuery polegającą na zwracaniu czegoś użytecznego, gdy dostają selektor dokumentu, a z formularzem Passed musisz coś zwrócić (myślę, że nie zrobiłbym tego, ale wstawiłem to po prostu pokazać „w środku”, że coś ma).

Oto skrzypcowa wersja tego dla ciekawskich: http://jsfiddle.net/az85G/

Mark Schultheiss
źródło
Nie rozumiem, w czym jest problem, że nic nie znajduje, kontekst, który podałeś dla jQuery, jest nulltaki, że .find('*').lengthzwraca 0 . Czy widzisz coś złego w tym (oczywistym) zachowaniu?
gdoron wspiera Monikę
@gdoron - nie znajduję nic złego w tym zachowaniu, po prostu chciałem zwrócić uwagę na różnicę w porównaniu z sytuacją, gdy ma selektor, który NIE jest zerowy - zwróć uwagę, że ten pusty selektor prawdopodobnie jest przyczyną odnotowania „szybszych” komentarzy gdzie indziej, ponieważ ma mniejszy obiekt do przetworzenia, ale zwraca obiekt, a nie „undefined” w tym przypadku. Jednak bardzo mi się podoba to pytanie i zagłosowałem za nim :)
Mark Schultheiss
Powodem jest to, że jest szybszy, ponieważ pierwszy warunek "złamania" ctora jest if(!selector) return thistaki, że jeśli dasz coś innego, są regexi inne rzeczy ... Dzięki za miłe słowa ... Myślę, że mógłbym poprosić zespół jQuery o odpowiedz na to (do diabła, to nie moja biblioteka :-)).
gdoron wspiera Monikę w
Tak, nie studiowałem tej konkretnej części bazy kodu, zhakowałem rdzeń, aby wprowadzić poprawki pośrednie dla błędów, ale nie tę część. Wolę teraz widzieć jQuery(document).ready(function(){});formularz w naszej bazie kodu, ponieważ istnieją różne poziomy wiedzy na temat jQuery i dla nowych ludzi jest "najbardziej oczywiste", że JEST to funkcja obsługi zdarzeń dla jQuery.
Mark Schultheiss
0

Myślę, że jest to bardziej czytelne niż cokolwiek innego.

Ten nie jest tak wyrazisty

$().ready(handler);

tak jak

$(document).ready(handler)

Być może próbują promować jakąś formę idiomatycznego jQuery.

Hyangelo
źródło
3
$(document).ready(handler)jest bardziej czytelny niż $(handler)zalecany ...
gdoron wspiera Monikę