w3school settimeout in javascript




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

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

topicId une erreur que topicId n'est pas défini Tout fonctionnait avant que topicId fonction setTimeout() .

Je veux que ma fonction postinsql(topicId) soit appelée après un certain temps. Que devrais-je faire?


@Jiri Vetyska merci pour le poste, mais il y a quelque chose de mal dans votre exemple. Je devais passer la cible qui est plané (ceci) à une fonction expirée et j'ai essayé votre approche. Testé dans IE9 - ne fonctionne pas. J'ai aussi fait quelques recherches et il semble que comme indiqué w3schools.com/jsref/met_win_settimeout.asp le troisième paramètre est le langage de script utilisé. Aucune mention sur les paramètres supplémentaires.

J'ai donc suivi la réponse de @ meder et résolu mon problème avec ce code:

$('.targetItemClass').hover(ItemHoverIn, ItemHoverOut);

function ItemHoverIn() {
 //some code here
}

function ItemHoverOut() {
    var THIS = this;
    setTimeout(
        function () { ItemHoverOut_timeout(THIS); },
        100
    );
}
function ItemHoverOut_timeout(target) {
    //do something with target which is hovered out
}

J'espère que c'est utile pour quelqu'un d'autre.


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 "ceci" pour pointer sur la fenêtre, ainsi vous perdrez votre référence d'objet.


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 de la métrique, c'est-à-dire 4 secondes plus tard, l'objet XHR peut ne pas être le même. Il est donc important de pré-lier les variables .


Comme il y a un problème avec le troisième paramètre optonal dans IE et l'utilisation de fermetures nous empêche de changer les variables (dans une boucle par exemple) et d'atteindre toujours le résultat souhaité, je suggère la solution suivante.

Nous pouvons essayer d'utiliser la récursion comme ceci:

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

Nous devons nous assurer que rien d'autre ne change ces variables et que nous écrivions une condition de récursivité appropriée pour éviter une récursion infinie.



En général, si vous devez passer une fonction en rappel avec des paramètres spécifiques, vous pouvez utiliser des fonctions d'ordre supérieur. C'est assez élégant avec ES6:

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

setTimeout(someFunction(params), 1000);

Ou si someFunction est premier ordre:

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

Je pense que tu veux:

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

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 sujet en interne. Cette valeur ne changera pas même si topicId à l'extérieur sera changé peu de temps 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);

La réponse de David Meister semble prendre en compte les paramètres qui peuvent changer immédiatement après l'appel de setTimeout () mais avant l'appel de la fonction anonyme. Mais c'est trop lourd et pas très évident. J'ai découvert une manière élégante de faire à peu près la même chose en utilisant IIFE (expression de fonction immédiatement invoquée).

Dans l'exemple ci-dessous, la variable currentList est transmise à l'IIFE, qui l'enregistre dans sa fermeture, jusqu'à ce que la fonction retardée soit invoquée. Même si la variable currentList change immédiatement après le code affiché, setInterval() fera le bon choix.

Sans cette technique IIFE, la fonction setTimeout() sera certainement appelée pour chaque élément h2 dans le DOM, mais tous ces appels ne verront que la valeur de texte du dernier élément 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>


Notez que la raison pour laquelle topicId était "non défini" par le message d'erreur est qu'il existait en tant que variable locale lorsque setTimeout était exécuté, mais pas lorsque l'appel différé à postinsql se produisait. La durée de vie variable est particulièrement importante à prendre en compte, en particulier lorsque vous essayez de faire passer "ceci" comme référence d'objet.

J'ai entendu que vous pouvez passer topicId en tant que troisième paramètre à la fonction setTimeout. Pas beaucoup de détails sont donnés mais j'ai assez d'informations pour le faire fonctionner, et c'est réussi dans Safari. Je ne sais pas ce qu'ils veulent dire à propos de "l'erreur milliseconde" cependant. Vérifiez le ici:

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


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 car cela appellera eval() sur la chaîne et à la place passer une fonction.


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 comptez jamais sur le fait de passer une chaîne comme une 'fonction' quand vous utilisez setTimeout() ou setInterval() , c'est plus lent car il faut l'évaluer 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 dans setTimeout en utilisant Function.prototype.bind()

Exemple:

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




settimeout