Pregunta

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

me sale un error que topicId no está definido que todo estaba funcionando antes de usar el setTimeout() función.

Quiero mi postinsql(topicId) función que se llamará después de un tiempo.¿Qué tengo que hacer?

¿Fue útil?

Solución

setTimeout(function() {
    postinsql(topicId);
}, 4000)

Es necesario para alimentar a una función anónima como un parámetro en lugar de una cadena, este último método no debe incluso trabajar por la especificación ECMAScript pero los navegadores son sólo indulgente. Esta es la solución correcta, no siempre se basan en pasar una cadena como una 'función' cuando se utiliza setTimeout() o setInterval(), es más lento porque tiene que ser evaluado y que no está bien.

ACTUALIZACIÓN:

Como dijo Hobblin en sus comentarios a la pregunta, ahora puede pasar argumentos a la función setTimeout dentro Function.prototype.bind() utilizando

Ejemplo:

setTimeout(postinsql.bind(null, topicId), 4000);

Otros consejos

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:

var hello = "Hello World";
setTimeout(alert, 1000, hello);

Más detalles:

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é que me gustaría mencionar otro enfoque que nadie ha mencionado aquí. Esto es copiado y pegado de la excelente subrayado biblioteca:

_.delay = function(func, wait) {
  var args = slice.call(arguments, 2);
  return setTimeout(function(){ return func.apply(null, args); }, wait);
};

Puede pasar tantos argumentos como desea la función llamada por setTimeout y como un bono adicional (así, por lo general un bono) el valor de los argumentos que se pasan a la función se congelan cuando se llama a setTimeout, por lo que si cambian de valor en algún punto entre cuando se llama a setTimeout () y cuando el tiempo de espera, bueno ... eso no es tan terriblemente frustrante más:)

Aquí hay un violín donde se puede ver lo que quiero decir.

Recientemente me encontré con la situación única de tener que utilizar un setTimeout en un bucle . Comprender esto puede ayudarle a entender cómo pasar parámetros a setTimeout.

Método 1

Utilice forEach y Object.keys, según sugerencia :

var testObject = {
    prop1: 'test1',
    prop2: 'test2',
    prop3: 'test3'
};

Object.keys(testObject).forEach(function(propertyName, i) {
    setTimeout(function() {
        console.log(testObject[propertyName]);
    }, i * 1000);
});

Recomiendo este método.

Método 2

Uso bind:

var i = 0;
for (var propertyName in testObject) {
    setTimeout(function(propertyName) {
        console.log(testObject[propertyName]);
    }.bind(this, propertyName), i++ * 1000);
}

jsFiddle: http://jsfiddle.net/MsBkW/

Método 3

O si usted no puede utilizar forEach o bind, utilizar un IIFE :

var i = 0;
for (var propertyName in testObject) {
    setTimeout((function(propertyName) {
        return function() {
            console.log(testObject[propertyName]);
        };
    })(propertyName), i++ * 1000);
}

Método 4

Sin embargo, si no se preocupan por IE <10, entonces se podría utilizar de Fabio sugerencia :

var i = 0;
for (var propertyName in testObject) {
    setTimeout(function(propertyName) {
        console.log(testObject[propertyName]);
    }, i++ * 1000, propertyName);
}

Método 5 (ES6)

Utilice una variable de bloque de ámbito:

let i = 0;
for (let propertyName in testObject) {
    setTimeout(() => console.log(testObject[propertyName]), i++ * 1000);
}

A pesar de que todavía recomendaríamos utilizando Object.keys con forEach en ES6.

Hobblin ya se comentó esto en la pregunta, pero debe ser una respuesta de verdad!

Uso Function.prototype.bind() es la forma más limpia y más flexible para hacer esto (con la ventaja añadida de ser capaz de establecer el contexto this):

setTimeout(postinsql.bind(null, topicId), 4000);

Para más información ver estos enlaces MDN:
https://developer.mozilla.org/en/docs/DOM/window.setTimeout#highlighter_547041 https://developer.mozilla.org/en/docs/JavaScript/Reference/ Global_Objects / Función / bind # With_setTimeout

Algunas respuestas son correctas, pero complicado.

Estoy respondiendo a esto de nuevo, 4 años más tarde, porque todavía ejecutar en código demasiado complejo para resolver exactamente esta pregunta. No es una solución elegante.

En primer lugar, no pase de una cadena como el primer parámetro al llamar setTimeout porque invoca efectivamente una llamada a la función lenta "eval".

Entonces, ¿cómo se pasa de un parámetro a una función de tiempo de espera? Mediante el uso de cierre:

settopic=function(topicid){
  setTimeout(function(){
    //thanks to closure, topicid is visible here
    postinsql(topicid);
  },4000);
}

...
if (xhr.readyState==4){
  settopic(xhr.responseText);
}

Algunos han sugerido el uso de la función anónima cuando se llama a la función de tiempo de espera:

if (xhr.readyState==4){
  setTimeout(function(){
    settopic(xhr.responseText);
  },4000);
}

La sintaxis funciona. Pero por el settopic tiempo se llama, es decir, 4 segundos más tarde, el objeto XHR puede no ser la misma. Por lo tanto es importante que pre-bind las variables .

Mi respuesta:

setTimeout((function(topicId) {
  return function() {
    postinsql(topicId);
  };
})(topicId), 4000);

Explicación:

  

La función anónima creada vuelve otra función anónima. Esta función tiene acceso a la topicId aprobado inicialmente, por lo que no va a cometer un error. La primera función anónima es llamado inmediatamente, pasando en topicId, por lo que la función registrada con un retraso tiene acceso a topicId en el momento de la llamada, a través de los cierres.

o

Esto convierte básicamente a:

setTimeout(function() {
  postinsql(topicId); // topicId inside higher scope (passed to returning function)
}, 4000);

EDIT: vi la misma respuesta, por lo miro a los suyos. Pero yo no robé su respuesta! Me olvidé de mirar. Lea la explicación y ver si ayuda a entender el código.

Reemplazar

 setTimeout("postinsql(topicId)", 4000);

con

 setTimeout("postinsql(" + topicId + ")", 4000);

o, mejor aún, sustituir la expresión de cadena con una función anónima

 setTimeout(function () { postinsql(topicId); }, 4000);

EDIT:

El comentario de Brownstone es incorrecta, esto funcionará como se pretende, como se ha demostrado mediante la ejecución de esto en la consola de Firebug

(function() {
  function postinsql(id) {
    console.log(id);
  }
  var topicId = 3
  window.setTimeout("postinsql(" + topicId + ")",4000); // outputs 3 after 4 seconds
})();

Tenga en cuenta que estoy en agreeance con otros que usted debe evitar pasar una cadena a setTimeout ya que esto le llame eval() en la cadena y en lugar de pasar una función.

La solución navegadores más fácil para apoyar parámetros en setTimeout:

setTimeout(function() {
    postinsql(topicId);
}, 4000)

Si no te importa no apoyar IE 9 e inferior:

setTimeout(postinsql, 4000, topicId);

setTimeout compatibilidad con los navegadores de escritorio

setTimeout la compatibilidad del navegador móvil

https://developer.mozilla.org/en- Estados Unidos / docs / web / API / WindowTimers / setTimeout

Sé que es antiguo, pero que quería añadir mi sabor (preferido) a esto.

Creo que una forma bastante legible para lograr esto es pasar la topicId a una función, que a su vez utiliza el argumento para hacer referencia al identificador de tema internamente. Este valor no cambiará aunque topicId en el exterior será cambiado poco después.

var topicId = xmlhttp.responseText;
var fDelayed = function(tid) {
  return function() {
    postinsql(tid);
  };
}
setTimeout(fDelayed(topicId),4000);

o corto:

var topicId = xmlhttp.responseText;
setTimeout(function(tid) {
  return function() { postinsql(tid); };
}(topicId), 4000);

La respuesta de David Meister parece cuidar de parámetros que pueden cambiar inmediatamente después de la llamada a setTimeout () pero antes de la función anónima que se llama. Pero es demasiado engorroso y no muy obvio. He descubierto una manera elegante de hacer más o menos lo mismo usando IIFE (expresión de la función de inmediato inviked).

En el siguiente ejemplo, la variable currentList se pasa a la IIFE, que guarda en su cierre, hasta que se invoca la función retardada. Incluso si la variable de currentList cambia inmediatamente después de que el código que se muestra, la setInterval() va a hacer lo correcto.

Sin esta técnica IIFE, la función setTimeout() conseguirá definitivamente llamada para cada elemento h2 en el DOM, pero todas esas llamadas sólo verá el valor de texto de la última elemento h2.

<script>
  // Wait for the document to load.
  $(document).ready(function() {
  $("h2").each(function (index) {

    currentList = $(this).text();

    (function (param1, param2) {
        setTimeout(function() {
            $("span").text(param1 + ' : ' + param2 );
        }, param1 * 1000);

    })(index, currentList);
  });
</script>

esto funciona en todos los navegadores (IE es un curioso)

setTimeout( (function(x) {
return function() {
        postinsql(x);
    };
})(topicId) , 4000);

En general, si usted necesita para pasar una función como una devolución de llamada con los parámetros específicos, puede utilizar funciones de orden superior. Esto es bastante elegante, con ES6:

const someFunction = (params) => () => {
  //do whatever
};

setTimeout(someFunction(params), 1000);

O si someFunction es de primer orden:

setTimeout(() => someFunction(params), 1000); 

Tenga en cuenta que la razón topicId "no estaba definido" por el mensaje de error es que existía como una variable local cuando se ejecutó la setTimeout, pero no cuando la llamada retardada a postinsql sucedió. tiempo de vida variable es especialmente importante prestar atención, especialmente cuando se trata de algo así como pasar "esto" como una referencia de objeto.

He oído que puede pasar topicId como tercer parámetro a la función setTimeout. Se da pocos detalles, pero tengo suficiente información para conseguir que funcione, y es un éxito en Safari. No sé lo que dicen acerca del "error de milisegundo" sin embargo. Échale un vistazo aquí:

http://www.howtocreate.co.uk/tutorials/javascript/timers

¿Cómo resolví esta etapa?

al igual que:

setTimeout((function(_deepFunction ,_deepData){
    var _deepResultFunction = function _deepResultFunction(){
          _deepFunction(_deepData);
    };
    return _deepResultFunction;
})(fromOuterFunction, fromOuterData ) , 1000  );

setTimeout esperar una referencia a una función, así que creé en un cierre, que interprete mis datos y devolver una función con un buen ejemplo de mis datos!

Tal vez se puede mejorar esta parte:

_deepFunction(_deepData);

// change to something like :
_deepFunction.apply(contextFromParams , args); 

he comprobado en Chrome, Firefox e IE y ejecutar así, no sé sobre el rendimiento, pero lo necesitaba para estar trabajando.

una prueba de muestra:

myDelay_function = function(fn , params , ctxt , _time){
setTimeout((function(_deepFunction ,_deepData, _deepCtxt){
            var _deepResultFunction = function _deepResultFunction(){
                //_deepFunction(_deepData);
                _deepFunction.call(  _deepCtxt , _deepData);
            };
        return _deepResultFunction;
    })(fn , params , ctxt)
, _time) 
};

// the function to be used :
myFunc = function(param){ console.log(param + this.name) }
// note that we call this.name

// a context object :
myObjet = {
    id : "myId" , 
    name : "myName"
}

// setting a parmeter
myParamter = "I am the outer parameter : ";

//and now let's make the call :
myDelay_function(myFunc , myParamter  , myObjet , 1000)

// this will produce this result on the console line :
// I am the outer parameter : myName

Tal vez se puede cambiar la firma para que sea más complient:

myNass_setTimeOut = function (fn , _time , params , ctxt ){
return setTimeout((function(_deepFunction ,_deepData, _deepCtxt){
            var _deepResultFunction = function _deepResultFunction(){
                //_deepFunction(_deepData);
                _deepFunction.apply(  _deepCtxt , _deepData);
            };
        return _deepResultFunction;
    })(fn , params , ctxt)
, _time) 
};

// and try again :
for(var i=0; i<10; i++){
   myNass_setTimeOut(console.log ,1000 , [i] , console)
}

Y finaly para responder a la pregunta original:

 myNass_setTimeOut( postinsql, 4000, topicId );

Espero que pueda ayudar!

ps: lo siento, pero Inglés no es mi lengua materna

!

Si desea pasar variable como parámetro permite probar esto

Si el requisito es función y var como parmas entonces prueba este

setTimeout((param1,param2) => { 
     alert(param1 + param2);
     postinsql(topicId);
},2000,'msg1', 'msg2')

Si el requisito es sólo variables como params entonces prueba este

setTimeout((param1,param2) => { alert(param1 + param2) },2000,'msg1', 'msg2')

Puede probar esto con ES5 y ES6

Puede probar la funcionalidad por defecto de 'apply ()' algo parecido a esto, se puede pasar a un mayor número de argumentos como su requisito en la matriz

function postinsql(topicId)
{
  //alert(topicId);
}
setTimeout(
       postinsql.apply(window,["mytopic"])
,500);

Puede pasar el parámetro a la función de devolución de llamada setTimeout como:

setTimeout (función, milisegundos, param1, param2, ...)

por ejemplo.

function myFunction() {
  setTimeout(alertMsg, 3000, "Hello");
}

function alertMsg(message) {
    alert(message)
}

ya que 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 así lograr el resultado deseado, sugiero la siguiente solución.

Podemos tratar de usar la recursividad como esto:

var i = 0;
var hellos = ["Hello World1!", "Hello World2!", "Hello World3!", "Hello World4!", "Hello World5!"];

if(hellos.length > 0) timeout();

function timeout() {                
    document.write('<p>' + hellos[i] + '<p>');
    i++;
    if (i < hellos.length)
        setTimeout(timeout, 500);
}

Hay que asegurarse de que nada cambia estas variables y que escribimos una condición adecuada para evitar la repetición de recursión infinita.

// Estos son tres respuestas muy simples y concisas:

function fun() {
    console.log(this.prop1, this.prop2, this.prop3);
}

let obj = { prop1: 'one', prop2: 'two', prop3: 'three' };

let bound = fun.bind(obj);

setTimeout(bound, 3000);

 // or

function funOut(par1, par2, par3) {

  return function() { 

    console.log(par1, par2, par3);

  }
};

setTimeout(funOut('one', 'two', 'three'), 5000);

 // or

let funny = function(a, b, c) { console.log(a, b, c); };

setTimeout(funny, 2000, 'hello', 'worldly', 'people');

Creo que desee:

setTimeout("postinsql(" + topicId + ")", 4000);

// Estos son tres respuestas muy simples y concisas:

function fun() {
    console.log(this.prop1, this.prop2, this.prop3);
}

let obj = { prop1: 'one', prop2: 'two', prop3: 'three' };

let bound = fun.bind(obj);

setTimeout(bound, 3000);

 // or

function funOut(par1, par2, par3) {

  return function() { 

    console.log(par1, par2, par3);

  }
};

setTimeout(funOut('one', 'two', 'three'), 5000);

 // or

let funny = function(a, b, c) { console.log(a, b, c); };

setTimeout(funny, 2000, 'hello', 'worldly', 'people');
scroll top