Question Comment puis-je passer un paramètre à un rappel setTimeout ()?


J'ai un code JavaScript qui ressemble à:

function statechangedPostQuestion()
{
  //alert("statechangedPostQuestion");
  if (xmlhttp.readyState==4)
  {
    var topicId = xmlhttp.responseText;
    setTimeout("postinsql(topicId)",4000);
  }
}

function postinsql(topicId)
{
  //alert(topicId);
}

J'ai une erreur topicId n'est pas défini Tout fonctionnait avant que j'utilise le setTimeout() fonction.

je veux mon postinsql(topicId) fonction à appeler après un certain temps. Que devrais-je faire?


676
2017-07-27 21:13


origine


Réponses:


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

Vous devez alimenter une fonction anonyme en tant que paramètre au lieu d'une chaîne, la dernière méthode ne devrait même pas fonctionner selon la spécification ECMAScript mais les navigateurs sont juste indulgents. C'est la bonne solution, ne jamais compter sur le passage d'une chaîne comme une «fonction» lors de l'utilisation setTimeout() ou setInterval()c'est plus lent parce que ça doit être évalué et ce n'est pas juste.

METTRE À JOUR:

Comme Hobblin a dit dans ses commentaires à la question, maintenant vous pouvez passer des arguments à la fonction à l'intérieur de setTimeout en utilisant Function.prototype.bind()

Exemple:

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

942
2017-07-27 21:15



Dans les navigateurs modernes, le "setTimeout" reçoit un troisième paramètre qui est envoyé comme paramètre à la fonction interne à la fin de la temporisation.

Exemple:

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

Plus de détails:


569
2017-09-21 17:23



Après quelques recherches et tests, la seule implémentation correcte est:

setTimeout(yourFunctionReference, 4000, param1, param2, paramN);

setTimeout passera tous les paramètres supplémentaires à votre fonction afin qu'ils puissent y être traités.

La fonction anonyme peut fonctionner pour des choses très basiques, mais dans l'instance d'un objet où vous devez utiliser "ceci", il n'y a aucun moyen de le faire fonctionner. Toute fonction anonyme changera "this" pour pointer sur la fenêtre, ainsi vous perdrez votre référence d'objet.


114
2017-10-30 22:08



C'est une très vieille question avec une réponse déjà "correcte" mais je pensais que je mentionnerais une autre approche que personne n'a mentionnée ici. Ceci est copié et collé à partir de l'excellente bibliothèque de soulignement:

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

Vous pouvez passer autant d'arguments que vous le souhaitez à la fonction appelée par setTimeout et comme bonus supplémentaire (généralement, un bonus) la valeur des arguments passés à votre fonction est gelée lorsque vous appelez setTimeout, donc s'ils changent de valeur à un certain moment entre l'appel de setTimeout () et son expiration, eh bien. .. ce n'est plus si horriblement frustrant :)

Voici un violon où vous pouvez voir ce que je veux dire - http://jsfiddle.net/thedavidmeister/7t2bV/


43
2017-12-18 14:28



Je suis récemment tombé sur la situation unique de devoir utiliser un setTimeout dans un boucle. Comprendre cela peut vous aider à comprendre comment transmettre des paramètres à setTimeout.

Méthode 1

Utilisation forEach et Object.keys, selon Sukima's suggestion:

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

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

Je recommande cette méthode.

Méthode 2

Utilisation 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éthode 3

Ou si vous ne pouvez pas utiliser forEach ou bind, utilisez un IIFE:

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

Méthode 4

Mais si vous ne vous souciez pas de IE <10, alors vous pouvez utiliser Fabio suggestion:

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

Méthode 5 (ES6)

Utilisez une variable de portée de bloc:

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

Bien que je recommanderais encore d'utiliser Object.keysavec forEach en ES6.


34
2017-07-09 19:58



Hobblin a déjà commenté la question, mais ça devrait être une réponse!

En utilisant Function.prototype.bind() est le moyen le plus propre et le plus flexible de le faire (avec l'avantage supplémentaire de pouvoir this le contexte):

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

Pour plus d'informations, voir ces liens 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


22
2018-03-25 16:34



Certaines réponses sont correctes mais alambiquées.

Je réponds à nouveau, 4 ans plus tard, parce que je rencontre toujours un code trop complexe pour résoudre exactement cette question. Il y a une solution élégante.

Tout d'abord, ne pas passer une chaîne comme premier paramètre lors de l'appel de setTimeout, car il appelle effectivement un appel à la fonction "eval" lente.

Alors, comment pouvons-nous transmettre un paramètre à une fonction de temporisation? En utilisant la fermeture:

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

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

Certains ont suggéré d'utiliser la fonction anonyme lors de l'appel de la fonction de temporisation:

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

La syntaxe fonctionne. Mais au moment de l'appel du métrique, c'est-à-dire 4 secondes plus tard, l'objet XHR peut ne pas être le même. Par conséquent, il est important de pré-lier les variables.


13
2018-01-19 06:00



Remplacer

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

avec

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

ou mieux encore, remplacez l'expression de chaîne par une fonction anonyme

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

MODIFIER:

Le commentaire de Brownstone est incorrect, cela fonctionnera comme prévu, comme démontré en l'exécutant dans la console Firebug

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

Notez que je suis d'accord avec les autres que vous devriez éviter de passer une chaîne à setTimeout comme cela appellera eval() sur la chaîne et à la place passer une fonction.


9
2017-07-27 21:16



Ma réponse:

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

Explication:

La fonction anonyme créée renvoie une autre fonction anonyme. Cette fonction a accès à l'original passé topicId, donc ça ne fera pas d'erreur. La première fonction anonyme est immédiatement appelée, passant topicId, donc la fonction enregistrée avec un retard a accès à topicId au moment de l'appel, à travers des fermetures.

OU

Cela se traduit essentiellement par:

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

EDIT: J'ai vu la même réponse, alors regarde la sienne. Mais je n'ai pas volé sa réponse! J'ai juste oublié de regarder. Lisez l'explication et voyez si cela aide à comprendre le code.


7
2018-06-01 03:27



La solution de navigateur croisé la plus simple pour prendre en charge les paramètres dans setTimeout:

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

Si cela ne vous dérange pas de ne pas supporter IE 9 et plus bas:

setTimeout(postinsql, 4000, topicId);

setTimeout desktop browser compatibility

setTimeout mobile browser compatibility

https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout


5
2017-11-20 11:07



Je sais que c'est vieux mais je voulais ajouter ma saveur (préférée) à cela.

Je pense qu'un moyen assez lisible pour y parvenir est de passer le topicId à une fonction, qui à son tour utilise l'argument pour référencer l'ID de rubrique en interne. Cette valeur ne changera pas même si topicId à l'extérieur sera changé peu après.

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

ou court:

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

3
2018-06-19 12:45