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 la setTimeout()
función.
Quiero postinsql(topicId)
que se llame mi función después de un tiempo. ¿Qué tengo que hacer?
javascript
parameters
callback
settimeout
Zeeshan Rang
fuente
fuente
Respuestas:
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 indulgentes. Esta es la solución adecuada, nunca confíes en pasar una cadena como una 'función' al usar
setTimeout()
osetInterval()
, es más lenta porque tiene que ser evaluada y simplemente no está bien.ACTUALIZAR:
Como dijo Hobblin en sus comentarios a la pregunta, ahora puede pasar argumentos a la función dentro de setTimeout usando
Function.prototype.bind()
.Ejemplo:
fuente
window.setTimeout
es un método DOM y, como tal, no está definido por la especificación ECMAScript. Pasar una cadena siempre ha funcionado en los navegadores, y es un estándar de facto ; de hecho, la capacidad de pasar un objeto de función se agregó más tarde, con JavaScript 1.2, forma parte explícita de la especificación de borrador HTML5 ( whatwg.org/specs/web -apps / current-work / multipage / ... ). Sin embargo, el uso de una cadena en lugar de un objeto de función generalmente se considera mal estilo porque es esencialmente una forma de retrasoeval()
.En los navegadores modernos, el "setTimeout" recibe un tercer parámetro que se envía como parámetro a la función interna al final del temporizador.
Ejemplo:
Más detalles:
fuente
Después de investigar y probar, la única implementación correcta es:
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 dentro de un objeto en el que debe usar "esto", no hay forma de hacerlo funcionar. Cualquier función anónima cambiará "esto" para que apunte a la ventana, por lo que perderá su referencia de objeto.
fuente
var that = this; setTimeout( function() { that.foo(); }, 1000);
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 subrayado :
Puede pasar tantos argumentos como desee a la función llamada por setTimeout y como un bono adicional (bueno, generalmente un bono) 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 cuando se llama a setTimeout () y cuando se agota el tiempo de espera, bueno ... eso ya no es tan horriblemente frustrante :)
Aquí hay un violín donde puedes ver lo que quiero decir.
fuente
Recientemente me encontré con la situación única de la necesidad de usar un
setTimeout
en un bucle . Comprender esto puede ayudarlo a comprender cómo pasar parámetros asetTimeout
.Método 1
Uso
forEach
yObject.keys
, según la sugerencia de Sukima :Recomiendo este método
Método 2
Uso
bind
:JSFiddle: http://jsfiddle.net/MsBkW/
Método 3
O si no puede usar
forEach
obind
, use un IIFE :Método 4
Pero si no te importa IE <10, entonces podrías usar la sugerencia de Fabio :
Método 5 (ES6)
Use una variable de ámbito de bloque:
Aunque todavía recomendaría usar
Object.keys
conforEach
ES6.fuente
.bind
no funcionará para IE8 y versiones inferiores [ref: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… ]. Terminé usando la solución de Schien: stackoverflow.com/a/21213723/1876899bind
, también estás en un entorno que ofreceObject.keys
yforEach
. Puede perder el bucle for y obtener un alcance de función "libre" (como en dos pájaros con una piedra libre y sin recursos) en el proceso.async
biblioteca ( github.com/caolan/async ). Lo usamos ampliamente en Sails y hemos tenido excelentes resultados durante los últimos 2 años. Se proporciona métodos tanto en paralelo y en serie para asíncronoforEach
,map
,reduce
, etc.Hobblin ya comentó esto sobre la pregunta, ¡pero debería ser una respuesta realmente!
Usar
Function.prototype.bind()
es la forma más limpia y flexible de hacerlo (con la ventaja adicional de poder establecer elthis
contexto):Para obtener más información, consulte estos enlaces de MDN:
https://developer.mozilla.org/en/docs/DOM/window.setTimeout#highlighter_547041 https://developer.mozilla.org/en/docs/JavaScript/Reference/Global_Objects/Function / bind # With_setTimeout
fuente
setTimeout(postinsql.bind(this, topicId), 4000);
bind
. Realmente crea un código legible.Algunas respuestas son correctas pero complicadas.
Estoy respondiendo esto nuevamente, 4 años después, porque todavía me encuentro con un código demasiado complejo para resolver exactamente esta pregunta. Hay una solución elegante.
En primer lugar, no pase una cadena como primer parámetro cuando llame a setTimeout porque invoca efectivamente una llamada a la función lenta "eval".
Entonces, ¿cómo pasamos un parámetro a una función de tiempo de espera? Mediante el uso de cierre:
Algunos han sugerido usar la función anónima al llamar a la función de tiempo de espera:
La sintaxis funciona. Pero cuando se llama al settopic de tiempo, es decir, 4 segundos después, el objeto XHR puede no ser el mismo. Por lo tanto, es importante vincular previamente las variables .
fuente
Mi respuesta:
Explicación:
O
Esto básicamente se convierte en:
EDITAR: Vi la misma respuesta, así que mira la suya. ¡Pero no robé su respuesta! Solo olvidé mirar. Lea la explicación y vea si ayuda a entender el código.
fuente
topicId
se altera el valor en el tiempo de espera también cambia. Un clon lo arreglóReemplazar
con
o mejor aún, reemplace la expresión de cadena con una función anónima
EDITAR:
El comentario de Brownstone es incorrecto, esto funcionará según lo previsto, como se demuestra al ejecutar esto en la consola Firebug
Tenga en cuenta que estoy de acuerdo con otros a los que debe evitar pasar una cadena,
setTimeout
ya que esto invocaráeval()
la cadena y en su lugar pasará una función.fuente
Puede pasar el parámetro a la función de devolución de llamada setTimeout como:
setTimeout (función, milisegundos, param1, param2, ...)
p.ej.
fuente
setTimeout( (p) => { console.log(p); }, 1000, "hi" );
La solución de navegador cruzado más fácil para admitir parámetros en setTimeout:
Si no le importa no admitir IE 9 y versiones inferiores:
https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout
fuente
Sé que han pasado 10 años desde que se hizo esta pregunta, pero aún así, si te has desplazado hasta aquí, supongo que todavía tienes algún problema. La solución de Meder Omuraliev es la más simple y puede ayudarnos a la mayoría de nosotros, pero para aquellos que no quieren tener ningún enlace, aquí está:
fuente
Sé que es viejo pero quería agregar mi sabor (preferido) a esto.
Creo que una forma bastante legible de lograr esto es pasarle
topicId
a una función, que a su vez usa el argumento para hacer referencia internamente al ID del tema. Este valor no cambiará incluso sitopicId
en el exterior se cambiará poco después.o corto:
fuente
La respuesta de David Meister parece ocuparse de los parámetros que pueden cambiar inmediatamente después de la llamada a setTimeout () pero antes de que se llame a la función anónima. Pero es demasiado engorroso y no muy obvio. Descubrí una forma elegante de hacer más o menos lo mismo usando IIFE (expresión de función invitada inmediatamente).
En el siguiente ejemplo, la
currentList
variable se pasa al IIFE, que la guarda en su cierre, hasta que se invoca la función retrasada. Incluso si la variablecurrentList
cambia inmediatamente después del código que se muestra,setInterval()
hará lo correcto.Sin esta técnica IIFE,
setTimeout()
definitivamente se llamará a la función para cadah2
elemento en el DOM, pero todas esas llamadas verán solo el valor de texto del últimoh2
elemento.fuente
En general, si necesita pasar una función como devolución de llamada con parámetros específicos, puede usar funciones de orden superior. Esto es bastante elegante con ES6:
O si
someFunction
es de primer orden:fuente
Tenga en cuenta que la razón por la que no se definió topicId según el mensaje de error es que existía como una variable local cuando se ejecutó setTimeout, pero no cuando ocurrió la llamada retrasada a postinsql. La vida útil variable es especialmente importante a la que se debe prestar atención, especialmente cuando se intenta algo como pasar "esto" como referencia de objeto.
Escuché que puede pasar topicId como tercer parámetro a la función setTimeout. No se dan muchos detalles, pero obtuve suficiente información para que funcione, y tiene éxito en Safari. Sin embargo, no sé qué significan sobre el "error de milisegundos". Compruébalo aquí:
http://www.howtocreate.co.uk/tutorials/javascript/timers
fuente
¿Cómo resolví esta etapa?
solo así:
¡setTimeout espera una referencia a una función, así que la creé en un cierre, que interpreta mis datos y devuelve una función con una buena instancia de mis datos!
Quizás puedas mejorar esta parte:
Lo probé en Chrome, Firefox e IE y se ejecuta bien, no sé sobre rendimiento, pero necesitaba que funcionara.
una prueba de muestra:
Tal vez pueda cambiar la firma para que sea más adecuada:
Y finalmente para responder la pregunta original:
Espero que pueda ayudar!
PD: lo siento, pero el inglés no es mi lengua materna.
fuente
esto funciona en todos los navegadores (IE es un bicho raro)
fuente
si quieres pasar variable como param intentemos esto
si el requisito es function y var como parmas, intente esto
si el requisito es solo variable como un parámetro, intente esto
Puedes probar esto con ES5 y ES6
fuente
Puede probar la funcionalidad predeterminada de 'apply ()' algo como esto, puede pasar más cantidad de argumentos como su requisito en la matriz
fuente
setTimeout es parte del DOM definido por WHAT WG.
https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html
El método que desea es: -
Aparentemente, los argumentos adicionales son compatibles con IE10. Alternativamente, puede usar
setTimeout(postinsql.bind(null, topicId), 4000);
, sin embargo, pasar argumentos adicionales es más simple, y eso es preferible.Factoid histórico: en días de VBScript, en JScript, el tercer parámetro de setTimeout era el lenguaje, como una cadena, por defecto a "JScript" pero con la opción de usar "VBScript". https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa741500(v%3Dvs.85)
fuente
@Jiri Vetyska gracias por la publicación, pero hay algo mal en tu ejemplo. Necesitaba pasar el objetivo que está suspendido (esto) a una función de tiempo de espera agotado y probé su enfoque. Probado en IE9: no funciona. También investigué un poco y parece que, como se señaló aquí, el tercer parámetro es el lenguaje de script que se está utilizando. No se mencionan parámetros adicionales.
Entonces, seguí la respuesta de @ meder y resolví mi problema con este código:
Espero que esto sea útil para alguien más.
fuente
Como hay un problema con el tercer parámetro optonal en IE y el uso de cierres nos impide cambiar las variables (en un bucle, por ejemplo) y aún lograr el resultado deseado, sugiero la siguiente solución.
Podemos intentar usar la recursividad de esta manera:
Necesitamos asegurarnos de que nada más cambie estas variables y que escribamos una condición de recursión adecuada para evitar una recursión infinita.
fuente
// Estas son tres respuestas muy simples y concisas:
fuente
Responde la pregunta pero con una simple función de suma con 2 argumentos.
fuente
Debe eliminar las comillas de su
setTimeOut
llamada de función de esta manera:fuente
Creo que quieres:
fuente
JSON.stringify
para objetos y matrices normales, y luego úseloJSON.parse
dentro de la función. Sin embargo, todo comportamiento se perderá si el objeto tiene métodos.// Estas son tres respuestas muy simples y concisas:
fuente