¿Cómo puedo pasar un parámetro a una devolución de llamada setTimeout()?
Tengo un código JavaScript que se parece a:
function statechangedPostQuestion()
{
//alert("statechangedPostQuestion");
if (xmlhttp.readyState==4)
{
var topicId = xmlhttp.responseText;
setTimeout("postinsql(topicId)",4000);
}
}
function postinsql(topicId)
{
//alert(topicId);
}
Recibo un error que topicId
no está definido. Todo funcionaba antes de usar elsetTimeout()
función.
Quiero postinsql(topicId)
que se llame a mi función después de un tiempo. ¿Qué tengo que hacer?
setTimeout(function() {
postinsql(topicId);
}, 4000);
Debe alimentar una función anónima como parámetro en lugar de una cadena. El último método ni siquiera debería funcionar, según la especificación ECMAScript, pero los navegadores son simplemente indulgentes. Ésta es la solución adecuada. Nunca confíes en pasar una cadena como una 'función' cuando uses setTimeout()
o setInterval()
. Es más lento, porque hay que evaluarlo y simplemente no está bien.
ACTUALIZAR:
Como dijo Hobblin en sus comentarios a la pregunta, ahora puedes pasar argumentos a la función dentro de setTimeout usando Function.prototype.bind()
.
Ejemplo:
setTimeout(postinsql.bind(null, topicId), 4000);
En los navegadores modernos (es decir, IE11 y posteriores), "setTimeout" recibe un tercer parámetro que se envía como parámetro a la función interna al final del temporizador.
Ejemplo:
var hello = "Hello World";
setTimeout(alert, 1000, hello);
Más detalles en función global setTimeout() - MDN
Después de investigar y probar un poco, la única implementación correcta es:
setTimeout(yourFunctionReference, 4000, param1, param2, paramN);
setTimeout pasará todos los parámetros adicionales a su función para que puedan procesarse allí.
La función anónima puede funcionar para cosas muy básicas, pero en el caso de un objeto donde tienes que usar "esto", no hay forma de hacer que funcione. Cualquier función anónima cambiará "esto" para que apunte a la ventana, por lo que perderá la referencia del objeto.
Esta es una pregunta muy antigua con una respuesta ya "correcta", pero pensé en mencionar otro enfoque que nadie ha mencionado aquí. Esto se copia y pega de la excelente biblioteca de guiones bajos :
_.delay = function(func, wait) {
var args = slice.call(arguments, 2);
return setTimeout(function(){ return func.apply(null, args); }, wait);
};
Puede pasar tantos argumentos como desee a la función llamada por setTimeout y, como beneficio adicional (bueno, generalmente un beneficio), el valor de los argumentos pasados a su función se congela cuando llama a setTimeout, por lo que si cambian de valor en algún momento entre el momento en que se llama a setTimeout() y el momento en que se agota el tiempo de espera, bueno... eso ya no es tan espantosamente frustrante :)
Aquí hay un violín donde puedes ver lo que quiero decir.