Почему «$ (). Ready (handler)» не рекомендуется?

88

С сайта документации API jQuery дляready

Все три из следующих синтаксисов эквивалентны:

  • $ (документ) .ready (обработчик)
  • $ (). ready (обработчик) (не рекомендуется)
  • $ (обработчик)

Выполнив домашнее задание - прочитав исходный код и поигравшись с ним , я понятия не имею, почему

$().ready(handler) 

не рекомендуется. Первый и третий способы абсолютно одинаковы, третий вариант вызывает функцию готовности кэшированного объекта jQuery с помощью document:

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

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

Но функция ready не взаимодействует с селектором выбранных узловых элементов. readyИсходный код:

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

Как видите, он просто добавляет обратный вызов во внутреннюю очередь ( readyList) и не изменяет и не использует элементы в наборе. Это позволяет вам вызывать readyфункцию для каждого объекта jQuery.

Подобно:

  • обычный селектор: $('a').ready(handler) DEMO
  • Селектор глупостей : $('fdhjhjkdafdsjkjriohfjdnfj').ready(handler) DEMO
  • Неопределенный селектор: $().ready(handler) DEMO

Напоследок ... на мой вопрос: почему $().ready(handler)не рекомендуется?

gdoron поддерживает Монику
источник
60
@ChaosPandion: Мне кажется, что он пытается понять инструменты, которые он использует, как свои пять пальцев. Я бы не назвал это потраченным зря усилием.
Джон
5
Хороший вопрос. Если кому-то интересно, вот сравнение производительности ... которое показывает (по крайней мере, в Chrome), что "нерекомендуемая" версия на самом деле самая быстрая.
Джеймс Аллардис,
5
Лучше спросить, почему они вообще существуют, это должен быть статический метод ( $.readyнапример) и в первую очередь не требовать создания объекта jQuery.
Esailija
2
@Esailija делает все возможное. Если jQuery не планирует предоставлять какие-то .ready()возможности для отдельных элементов, не должно быть причин для создания объекта jQuery.
2
@ChaosPandion. Вы не можете использовать это ... $.readyуже занято внутренней функцией jQuery, найдите в исходном коде ready:.
gdoron поддерживает Монику

Ответы:

88

Получил официальный ответ от одного из разработчиков jQuery:

$().ready(fn)работает только потому, что $()раньше был ярлыком для $(document) (jQuery <1.4)
Так $().ready(fn)был читаемый код.

Но люди совершали подобные вещи $().mouseover()и прочие безумие.
и люди должны были $([])получить пустой объект jQuery

Итак, в 1.4 мы изменили его так, чтобы он $()давал пустой jQuery, и мы просто сделали $().ready(fn)работу, чтобы не сломать много кода.

$().ready(fn) буквально сейчас просто пропатчен в ядре, чтобы он работал должным образом в устаревшем случае.

Лучшее место для readyфункции есть $.ready(fn), но это действительно старое дизайнерское решение, и это то, что у нас есть сейчас.


Я спросил его:

Вы думаете, что $ (fn) более читабельна, чем $ (). Ready (fn)?!

Его ответ был:

Я всегда использую $ (document) .ready (fn) в реальных приложениях, и обычно в приложении есть только один блок готовых документов, это не совсем похоже на обслуживание.

Я думаю, что $ (fn) тоже довольно нечитабельно , это просто вещь, которую вы должны знать, работает ™ ...

gdoron поддерживает Монику
источник
1
Имеет смысл, jQuery довольно серьезно относится к обратной совместимости
Esailija
@Esailija: Если бы они были , что серьезно, они бы не перешли на поведение $()в первую очередь (как бестолковый , как поведение может быть) . С другой стороны, ты прав. Они не всегда так склонны вносить критические изменения, как было показано, когда они пытались что-то изменить .attr(), а через несколько дней быстро вернулись. Это связывало их с некоторыми из их неудачных дизайнерских решений в раннем (и среднем) возрасте.
3
@gdoron +1 за то, что достал прямо изо рта лошади.
2
@gdoron +1 за настоящий ответ. И да, мы были довольно близки в своем восприятии.
VisioN
" Это просто вещь, которую вы должны знать, работает ™ ..." Ну, так $(selector[, context])и есть $(html[, ownerDocument]). Фактически, вы можете просто использовать jQuery()вместо этого, $()если проблема заключается в том, чтобы знать, что он работает. Или зачем вообще использовать jQuery?
JAB
11

Поскольку разные варианты делают примерно то же самое, что вы указываете, пора надеть шляпу писателя библиотеки и сделать некоторые предположения.

  1. Возможно, люди, использующие jQuery, хотели бы иметь $()доступ к нему для будущего использования (сомнительно, поскольку $().readyдокументально подтверждено, что оно работает, даже если оно не рекомендуется; это также испортит семантику $особого случая).

  2. Гораздо более практичная причина: вторая версия - единственная, которая не завершается упаковкой document, поэтому ее легче сломать при поддержке кода. Пример:

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

    Сравните это с

    // BEFORE
    $().ready(foo);
    
    // AFTER: breaks
    $().ready(foo).on("click", "a", function() {});
    
  3. В связи с вышеизложенным: readyэто урод в том смысле, что это (единственный?) Метод, который будет работать одинаково независимо от того, что объект jQuery обертывает (даже если он ничего не обертывает, как здесь). Это серьезное отличие от семантики других методов jQuery, поэтому полагаться на него не рекомендуется.

    Обновление: как указывает комментарий Esailija, с инженерной точки зрения readyдействительно должен быть статический метод именно потому, что он работает так.

Обновление №2: копаясь в источнике, кажется, что в какой-то момент ветка 1.4 $()была изменена, чтобы соответствовать $([]), а в 1.3 она вела себя как $(document). Это изменение усилит приведенные выше обоснования.

Джон
источник
Я никогда не видел такого кода, старая идиома была$(document).ready( function(){ //your code here } );
Esailija
Я не мог понять второе обновление, не могли бы вы уточнить еще немного? Я искал более старые версии, но не нашел никакой разницы в этой проблеме с пустым объектом jQuery.
gdoron поддерживает Монику
@gdoron: Я имею в виду изменение с selector = selector || documentна if(!selector) return this.
Джон
4

Я бы сказал, что это просто тот факт, что $()возвращает пустой объект, тогда $(document)как вы не применяете его ready()к разным вещам; он все еще работает, но я бы сказал, что это не интуитивно понятно.

$(document).ready(function(){}).prop("title") // the title
$().ready(function(){}).prop("title")  //null - no backing document
Алекс К.
источник
1
Да, в этом ответе те же представления . Таким образом, изменения произошли в версии 1.4, которая выпустила новую политику возврата.
VisioN
Я никогда не видел, чтобы кто-то менял заголовок документа при присоединении готового обратного вызова, и вы можете просто сделать это с помощью vanilla js без jQuery . Я не говорю, что это может быть ответ, но это не веская причина.
gdoron поддерживает Монику
Никакие свойства или методы документа не могут быть связаны через$()
Alex K.
2
@AlexK. его точка зрения заключалась в том, что на самом деле никто на самом деле не цепляет после, .readyпотому что это устоявшаяся идиома. Конечно, есть теоретическая вероятность того, что кто-то сделает это, но я никогда не видел, чтобы код делал это (что не является хорошим аргументом, но вы знаете: D).
Esailija
2
Возможно, из-за этой теоретической случайности метод не рекомендуется , так как он ведет себя по-разному в разных выпусках.
VisioN
3

Скорее всего, это просто ошибка документации, и ее следует исправить, единственный недостаток использования $().ready(handler)- это удобочитаемость. Конечно, утверждать, что $(handler)это так же нечитабельно. Согласен, поэтому не использую .

Вы также можете возразить, что один метод быстрее другого. Однако как часто вы вызываете этот метод достаточно раз подряд на одной странице, чтобы заметить разницу?

В конечном итоге все сводится к личным предпочтениям. Нет никаких недостатков в использовании $().ready(handler)другого аргумента, кроме удобочитаемости. Я думаю, что в этом случае документация неверна.

Кевин Б.
источник
+1! Вы были абсолютно правы! Вам понравится прочитать официальный ответ jQuery. Я добавил это как ответ.
gdoron поддерживает Монику
2

Просто чтобы сделать очевидным, что есть некоторая несогласованность в трех, плюс я добавил четвертую часто используемую форму: (function($) {}(jQuery));

С такой разметкой:

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

и этот код:

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

Отображаемые результаты div из последнего оператора: 0: 9: 9: 9: undefined

Итак, только версии Handler и Doc согласуются с соглашением jQuery о возврате чего-то полезного, поскольку они получают селектор документов, и с формой Passed вы должны что-то вернуть (я бы не стал этого делать, я бы подумал, но просто вставьте это в показать "внутри" есть что).

Вот его версия для любопытных: http://jsfiddle.net/az85G/

Марк Шультайс
источник
Я не понимаю, в чем проблема, что он ничего не находит, контекст, который вы указали для jQuery, nullтак что .find('*').lengthвозвращает 0 . Вы находите что-то плохое в этом (очевидном) поведении?
gdoron поддерживает Монику
@gdoron - я не нахожу ничего плохого в этом поведении, я просто хотел указать на разницу по сравнению с тем, когда у него ДЕЙСТВИТЕЛЬНО есть селектор, который НЕ НУЛЬ - обратите внимание, что этот пустой селектор, вероятно, является причиной того, что «более быстрые» комментарии отмечены в другом месте, поскольку он имеет меньший объект для обработки, но ДЕЙСТВИТЕЛЬНО возвращает объект, а не "undefined" в этом случае. Мне действительно нравится этот вопрос, и я проголосовал за него :)
Марк Шультайс
Причина в том, что это быстрее, потому что первое условие "разрыва" ctor - это if(!selector) return thisесли вы дадите что-то еще, есть regexи другие вещи ... Спасибо за добрые слова ... Думаю, я мог бы попросить команду jQuery ответь на это (черт возьми, это не моя библиотека :-)).
gdoron поддерживает Монику
Да, я не изучал эту конкретную часть базы кода, я взломал ядро, чтобы внести промежуточные исправления для ошибок, но не эту часть. Я ДЕЙСТВИТЕЛЬНО предпочитаю видеть эту jQuery(document).ready(function(){});форму в нашей базе кода в настоящее время, поскольку существуют разные уровни опыта jQuery, и для новичков «наиболее очевидно», что это функция обработчика событий для jQuery.
Марк Шультайс
0

Я думаю, что это больше для удобочитаемости, чем что-либо еще.

Этот не такой выразительный

$().ready(handler);

в качестве

$(document).ready(handler)

Возможно, они пытаются продвигать какую-то форму идиоматического jQuery.

Hyangelo
источник
3
$(document).ready(handler)более читабелен, чем $(handler)рекомендованный ...
gdoron поддерживает Монику