¿Por qué no se recomienda "$ (). Ready (handler)"?

88

Desde el sitio de documentos de la API de jQuery paraready

Las tres siguientes sintaxis son equivalentes:

  • $ (documento) .ready (controlador)
  • $ (). ready (controlador) (esto no se recomienda)
  • $ (manejador)

Después de hacer la tarea: leer y jugar con el código fuente , no tengo idea de por qué

$().ready(handler) 

no es recomendado. La primera y la tercera forma son exactamente iguales, la tercera opción llama a la función lista en un objeto jQuery almacenado en caché con document:

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

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

Pero la función lista no tiene interacción con el selector de los elementos de nodo seleccionados, el readycódigo fuente:

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

Como puede ver, simplemente agrega la devolución de llamada a una cola interna ( readyList) y no cambia ni usa los elementos del conjunto. Esto le permite llamar a la readyfunción en cada objeto jQuery.

Me gusta:

  • selector regular : $('a').ready(handler) DEMO
  • Selector de tonterías : $('fdhjhjkdafdsjkjriohfjdnfj').ready(handler) DEMO
  • Selector indefinido : $().ready(handler) DEMO

Finalmente ... a mi pregunta: ¿Por qué $().ready(handler)no se recomienda?

gdoron está apoyando a Monica
fuente
60
@ChaosPandion: Para mí, parece que se esfuerza por comprender las herramientas que usa como la palma de su mano. No llamaría exactamente a eso un esfuerzo inútil.
Jon
5
Buena pregunta. Si alguien está interesado, aquí hay una comparación de rendimiento ... que muestra (al menos en Chrome) que la versión "no recomendada" es en realidad la más rápida.
James Allardice
5
Una mejor pregunta es por qué estos existen, debería ser un método estático ( $.readypor ejemplo) y no requerir la construcción de un objeto jQuery en primer lugar.
Esailija
2
@Esailija hace lo mejor de todo. A menos que jQuery planee proporcionar algún tipo de .ready()capacidad para elementos individuales, no debería haber ninguna razón para construir un objeto jQuery.
2
@ChaosPandion. No puede usar eso ... $.readyya está tomado por una función interna de jQuery, busque el código fuente ready:.
gdoron apoya a Monica

Respuestas:

88

Recibí una respuesta oficial de uno de los desarrolladores de jQuery:

$().ready(fn) solo funciona porque $() solía ser un acceso directo a $(document) (jQuery <1.4)
También lo $().ready(fn)era un código legible.

Pero la gente solía hacer cosas similares $().mouseover()y todo tipo de locuras.
y la gente tuvo que hacer $([])para obtener un objeto jQuery vacío

Así que en 1.4 lo cambiamos $() da un jQuery vacío y simplemente lo hicimos $().ready(fn)funcionar para no romper mucho código

$().ready(fn) literalmente ahora está parcheado en el núcleo para que funcione correctamente para el caso heredado.

El mejor lugar para el ready función es $.ready(fn), pero es una decisión de diseño realmente antigua y eso es lo que tenemos ahora.


Le pregunté:

¿Crees que $ (fn) es más legible que $ (). Ready (fn)?!

Su respuesta fue:

Siempre hago $ (document) .ready (fn) en aplicaciones reales y, por lo general, solo hay un bloque listo para documentos en la aplicación, no es exactamente como una cosa de mantenimiento.

Creo que $ (fn) también es bastante ilegible , es solo una cosa que debes saber que funciona ™ ...

gdoron está apoyando a Monica
fuente
1
Tiene sentido, jQuery es bastante serio acerca de la compatibilidad hacia atrás
Esailija
@Esailija: Si fueran tan serios, no habrían cambiado el comportamiento de $()en primer lugar (por muy tonto que haya sido ese comportamiento) . Por otro lado, tienes razón. No siempre están tan inclinados a hacer cambios importantes, como se demostró cuando intentaron cambiar .attr()y luego hicieron una reversión rápida unos días después. Esto los ha vinculado a algunas de sus desafortunadas decisiones de diseño tempranas (y de mediana edad).
3
@gdoron +1 por sacarlo directamente de la boca del caballo.
2
@gdoron +1 por obtener la respuesta real. Y sí, hemos estado bastante cerca en nuestras percepciones.
VisioN
" Es solo una cosa que debes saber que funciona ™ ..." Bueno, también lo son $(selector[, context])y $(html[, ownerDocument]). De hecho, también podría usarlo en jQuery()lugar de $()si el problema es tener que saberlo. ¿O por qué usar jQuery?
JAB
11

Dado que las diferentes opciones hacen prácticamente lo mismo que usted señala, es hora de ponerse el sombrero de escritor de la biblioteca y hacer algunas conjeturas.

  1. Quizás a la gente de jQuery le gustaría tener $()disponible para uso futuro (dudoso ya que $().readyestá documentado para funcionar, incluso si no se recomienda; también contaminaría la semántica de $si fuera un caso especial).

  2. Una razón mucho más práctica: la segunda versión es la única que no acaba envolviéndose document, por lo que es más fácil de romper al mantener el código. Ejemplo:

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

    Contrasta esto con

    // BEFORE
    $().ready(foo);
    
    // AFTER: breaks
    $().ready(foo).on("click", "a", function() {});
    
  3. Relacionado con lo anterior: readyes un fenómeno en el sentido de que es (¿el único?) Método que funcionará igual sin importar lo que envuelva el objeto jQuery (incluso si no envuelve nada como es el caso aquí). Esta es una gran diferencia con la semántica de otros métodos de jQuery, por lo que no se recomienda confiar específicamente en esto.

    Actualización: como señala el comentario de Esailija, desde una perspectiva de ingeniería, readydebería ser un método estático exactamente porque funciona así.

Actualización # 2: Excavando en la fuente, parece que en algún momento en la rama 1.4 $()se cambió para coincidir $([]), mientras que en 1.3 se comportó como $(document). Este cambio reforzaría las justificaciones anteriores.

Jon
fuente
Sin embargo, nunca había visto un código como este, el antiguo modismo era$(document).ready( function(){ //your code here } );
Esailija
No pude entender la segunda actualización, ¿puedes dar más detalles, por favor? Busqué versiones anteriores, pero no pude encontrar ninguna diferencia para este problema de objeto jQuery vacío.
gdoron apoya a Monica
@gdoron: Me refiero al cambio de selector = selector || documenta if(!selector) return this.
Jon
4

Yo diría que es simplemente el hecho de que $()devuelve un objeto vacío, mientras $(document)que no lo hace su aplicación ready()a diferentes cosas; todavía funciona, pero yo diría que no es intuitivo.

$(document).ready(function(){}).prop("title") // the title
$().ready(function(){}).prop("title")  //null - no backing document
Alex K.
fuente
1
Sí, las mismas percepciones están en esta respuesta . Entonces, los cambios tuvieron lugar en la versión 1.4, que lanzó una nueva política de devolución.
VisioN
Nunca he visto a alguien cambiar el título del documento mientras adjunta una devolución de llamada lista, y simplemente puede hacerlo con vanilla js sin jQuery . No digo que no sea la respuesta, pero no es una buena razón.
gdoron apoya a Monica
Así no hay propiedades de los documentos o los métodos pueden ser encadenados a través de$()
Alex K.
2
@AlexK. su punto era que nadie en realidad se encadena después .readyporque es un idioma bien establecido no hacerlo. Seguro que hay una posibilidad teórica de que alguien haga esto, pero nunca he visto código haciendo eso (lo cual no es un buen argumento, pero ya sabes: D).
Esailija
2
Quizás debido a este método de azar teórico no se recomienda , ya que tiene un comportamiento diferente en diferentes versiones.
VisioN
3

Lo más probable es que esto sea solo un error de documentación y debería corregirse, el único inconveniente de usar $().ready(handler)es su legibilidad. Claro, argumenta que $(handler)es igualmente ilegible. Estoy de acuerdo, por eso no lo uso .

También puede argumentar que un método es más rápido que otro. Sin embargo, ¿con qué frecuencia llama a este método suficientes veces seguidas en una sola página para notar una diferencia?

En última instancia, todo se reduce a las preferencias personales. No hay inconveniente en usar $().ready(handler)otro que no sea el argumento de legibilidad. Creo que la documentación es errónea en este caso.

Kevin B
fuente
+1! ¡Tenías toda la razón! Le encantará leer la respuesta oficial de jQuery. Lo agregué como respuesta.
gdoron apoya a Monica
2

Solo para que sea claramente obvio que hay alguna inconsistencia en los tres, además agregué la cuarta forma de uso frecuente: (function($) {}(jQuery));

Con este marcado:

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

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

Los resultados mostrados del div de la última declaración son: 0: 9: 9: 9: indefinido

Entonces, solo las versiones Handler y Doc son consistentes con la convención jQuery de devolver algo de uso a medida que obtienen el selector de documentos y con el formulario Pasado debe devolver algo (yo no haría esto, creo, pero póngalo solo para mostrar "adentro" tiene algo).

Aquí hay una versión de violín de esto para los curiosos: http://jsfiddle.net/az85G/

Mark Schultheiss
fuente
No puedo ver cuál es el problema con que no encuentra nada, el contexto que proporcionó para jQuery es, nullpor lo tanto, .find('*').lengthdevuelva 0 . ¿Encuentra algo malo con este comportamiento (obvio)?
gdoron apoya a Monica
@gdoron: no encuentro nada malo con este comportamiento, solo quería señalar la diferencia en comparación con cuando TIENE un selector que NO es nulo; tenga en cuenta que este selector vacío es probablemente la razón por la que se notan los comentarios "más rápidos" en otros lugares, ya que tiene un objeto más pequeño para procesar, pero devuelve un objeto y no "indefinido" en esa instancia. Sin embargo, me gusta mucho la pregunta y la voté :)
Mark Schultheiss
La razón es por qué es más rápido, porque la primera condición de "ruptura" del ctor es if(!selector) return thissi das algo más, hay regexy otras cosas sucediendo ... Gracias por tus amables palabras ... Creo que podría pedirle al equipo de jQuery que responde esto (diablos, no es mi biblioteca :-)).
gdoron apoya a Monica
Sí, no he estudiado esta parte en particular de la base del código, he pirateado el núcleo para corregir errores internos, pero no esa parte. Prefiero ver el jQuery(document).ready(function(){});formulario en nuestra base de código en la actualidad, ya que existen diferentes niveles de experiencia en jQuery y es "más obvio" para la gente nueva que ES una función de controlador de eventos para jQuery.
Mark Schultheiss
0

Creo que esto es más por legibilidad que por cualquier otra cosa.

Este no es tan expresivo

$().ready(handler);

como

$(document).ready(handler)

Quizás estén tratando de promover alguna forma de jQuery idiomática.

Hyangelo
fuente
3
$(document).ready(handler)es más legible de lo $(handler)que se recomienda ...
gdoron apoya a Monica