¿Por qué este bloque de código está creando un bucle infinito?
Frecuentes
Visto 408 veces
1
Estaba jugando con un violín hoy mientras intentaba responder una pregunta y encontré algo confuso. Siendo un novato de JS, no puedo depurar lo que está mal. Incluso traté de verificar la fuente 0 de $.fn.show
en la fuente de jQuery, pero no pude averiguar qué está pasando mal.
HTML:
<input type='text' id='dataBox'/>
<input type='button' value='toggle' id='toggleButton' />
código jQuery:
jQuery(function ($) {
var _oldShow = $.fn.show;
$.fn.show = function (speed, oldCallback) {
return $(this).each(function () {
var obj = $(this),
newCallback = function () {
if ($.isFunction(oldCallback)) {
oldCallback.apply(obj);
}
obj.trigger('afterShow');
};
obj.trigger('beforeShow');
if(speed)
_oldShow.apply(obj, [speed,newCallback]);
else
_oldShow.apply(obj, [newCallback]);
});
}
});
$('#dataBox').bind('beforeShow', function () {
alert('beforeShow');
});
$('#toggleButton').click(function(){
$('#dataBox').show();
});
El problema es que por algún error que cometí, está causando que esta línea se ejecute un número infinito de veces obj.trigger('beforeShow');
y de ahí el alert
en este bloque
$('#dataBox').bind('beforeShow', function () {
alert('beforeShow');
});
parece no parar.
Independientemente de lo que estoy tratando de hacer o si esto se puede hacer de otra manera, ¿alguien puede explicar qué estoy haciendo mal aquí? He estado intentando durante varias horas, pero no pude averiguarlo.
3 Respuestas
2
Echemos un vistazo a esta sección.
if(speed)
_oldShow.apply(obj, [speed,newCallback]);
else
_oldShow.apply(obj, [newCallback]);
});
_oldShow
se asigna como $.fn.show;
antes, y .apply()
llama a una función con argumentos como una matriz y la capacidad de establecer el contexto de this
. (ver aquí)
Entonces, al final de la función, siempre terminamos llamando a la función nuevamente, activando infinitamente beforeShow.
contestado el 22 de mayo de 12 a las 17:05
Si observa el código detenidamente, puede ver que en él la función $.fn.show acaba de envolverse con otra función que llama a la original, no a sí misma. - Dmitry
@Dmitry No entiendo lo que intentas decir. _oldShow
es igual a la función anónima que contiene la función que contiene el bloque if anterior, llamándose a sí misma infinitamente. - Snuffleupagus
para verificar su teoría, puede alertar algo como esto: "alert ($.fn.show === _oldShow);". Ejemplo: jsfiddle.net/D9vP6 si lo hace, puede ver que las funciones son diferentes. - Dmitry
@Dmitry Todavía no tienes ningún sentido. Todo lo que probaste es que la función se llama a sí misma a una recursividad infinita, que era lo que explicaba mi respuesta. - Snuffleupagus
Pero estoy haciendo una copia de $.fn.show
en la primera linea var _oldShow = $.fn.show;
¿Solo hace referencia a $.fn.show
y no una copia duplicada de la función. Parece que tienes razón. Pero entonces, ¿cómo puedo hacer una copia de $.fn.show
y usar eso más tarde? - Prasenjit Kumar Nag
1
Mire el código de la función show (está en alerta): http://jsfiddle.net/D9vP6/4/
Parecía llamarse a sí mismo bajo alguna condición para normalizar el argumento. Después de redefinir esta función, recibe una recursividad infinita.
Para evitar tal comportamiento, debe tener todo esto normalizado en su código y no desencadenar eventos bajo algunas condiciones.
contestado el 22 de mayo de 12 a las 17:05
en realidad es el original $.fn.show
. Mira esto jsfiddle.net/joycse06/evdpj/3 +1 por esto. - Prasenjit Kumar Nag
@Joy, sí lo es y trata de llamarse a sí mismo, lo que en realidad ya no es él mismo, ya que se redefinió. Entonces te llama función en lugar de eso, que llama original y así sucesivamente. - Dmitry
1
El problema con el código anterior es que en algún momento jQuery llama al $.fn.show
desde dentro de sí mismo y eso crea el bucle infinito. Entonces, la forma correcta de evitar eso es hacer una verificación de argumentos como la siguiente:
jQuery(function($) {
var _oldShow = $.fn.show;
$.fn.show = function(speed, easing, oldCallback) {
var args = Array.prototype.slice.call(arguments),
duration = args[0] || 0,
easing = 'linear',
callback = function() {},
callbackArgIndex = 1;
// jQuery recursively calls show sometimes; we shouldn't
// handle such situations. Pass it to original show method.
if (!this.selector) {
_oldShow.apply(this, args);
return this;
}
if (args.length === 2) {
if ($.isFunction(args[1])) {
callback = args[1];
callbackArgIndex = 1;
}
else {
easing = args[1];
}
}
else if (args.length === 3) {
easing = args[1];
callback = args[2];
callbackArgIndex = 2;
}
return this.each(function() {
var obj = $(this),
oldCallback = callback,
newCallback = function() {
if ($.isFunction(oldCallback)) {
oldCallback.apply(obj);
}
obj.trigger('afterShow');
};
obj.trigger('beforeShow');
args[0] = duration;
if (callback) {
args[callbackArgIndex] = newCallback;
}
else {
args.push(callback);
}
_oldShow.apply(obj, args);
});
}
});
$('#dataBox').bind('beforeShow afterShow', function(e) {
alert(e.type);
});
$('#toggleButton').click(function() {
$('#dataBox').show();
});
Esto funciona bien y los eventos se activan correctamente.
El bloque que impide el ciclo infinito es este
if (!this.selector) {
_oldShow.apply(this, args);
return this;
}
Lo que esto está haciendo es llamar a la función original y regresar en los casos en que jQuery llama $.fn.show
varias veces (jQuery parece estar haciéndolo por alguna razón).
contestado el 30 de mayo de 12 a las 08:05
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas javascript jquery or haz tu propia pregunta.
Una sugerencia para facilitar la depuración. Usa la declaración
debugger;
en lugar dealert('beforeShow');
en su método de enlace. Esto colocará un punto de interrupción allí para que pueda ver el seguimiento de la pila en el depurador. - Brant Olsen@BrantOlsen
debugger;
funciona con Visual Studio, supongo que si el OP está usando php o no está del lado del servidor, por ejemplo,console.log
sería una mejor sugerencia - Rafay@3nigma También funciona con Chrome y Firebug. - Brant Olsen
@BrantOlsen que no sabía, gracias por compartir - Rafay
@BrantOlsen Gracias por el
debugger;
declaración. - Prasenjit Kumar Nag