it-swarm.com.de

Wie kann ich einen Parameter an einen setTimeout () - Rückruf übergeben?

Ich habe JavaScript-Code, der wie folgt aussieht:

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

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

Ich erhalte die Fehlermeldung, dass topicId nicht definiert ist Alles funktionierte, bevor ich die Funktion setTimeout() verwendete. 

Ich möchte, dass meine postinsql(topicId)-Funktion nach einiger Zeit aufgerufen wird. Was soll ich machen?

727
Zeeshan Rang
setTimeout(function() {
    postinsql(topicId);
}, 4000)

Sie müssen eine anonyme Funktion als Parameter anstelle einer Zeichenfolge verwenden. Die letztere Methode sollte nicht einmal gemäß der ECMAScript-Spezifikation funktionieren, aber Browser sind nur nachsichtig. Dies ist die richtige Lösung. Verlassen Sie sich nicht auf die Übergabe einer Zeichenfolge als "Funktion", wenn Sie setTimeout() oder setInterval() verwenden. Sie ist langsamer, da sie ausgewertet werden muss und nicht stimmt.

UPDATE:

Wie Hobblin in seinen Kommentaren zu der Frage sagte, können Sie jetzt mit Function.prototype.bind() Argumente an die Funktion in setTimeout übergeben.

Beispiel:

setTimeout(postinsql.bind(null, topicId), 4000);
1010
meder omuraliev

In modernen Browsern erhält der "setTimeout" einen dritten Parameter, der am Ende des Timers als Parameter an die interne Funktion gesendet wird.

Beispiel:

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

Mehr Details:

626
Fabio Phms

Nach einigen Recherchen und Tests ist die einzig korrekte Implementierung:

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

setTimeout übergibt alle zusätzlichen Parameter an Ihre Funktion, damit sie dort verarbeitet werden können.

Die anonyme Funktion kann für sehr einfache Dinge verwendet werden, aber innerhalb der Instanz eines Objekts, für das Sie "this" verwenden müssen, gibt es keine Möglichkeit, sie zum Laufen zu bringen. __ Jede anonyme Funktion ändert "this" in "window". So verlieren Sie Ihre Objektreferenz.

121
Jiri Vetyska

Dies ist eine sehr alte Frage mit einer bereits "richtigen" Antwort, aber ich dachte, ich würde einen anderen Ansatz erwähnen, den niemand hier erwähnt hat. Dies wird aus der exzellenten Unterstrich Bibliothek kopiert und eingefügt:

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

Sie können beliebig viele Argumente an die von setTimeout und aufgerufene Funktion als zusätzlichen Bonus (normalerweise einen Bonus) übergeben. Der Wert der an Ihre Funktion übergebenen Argumente wird eingefroren, wenn Sie setTimeout aufrufen Wenn sich der Wert irgendwann zwischen dem Aufruf von setTimeout () und dem Zeitlimit ändert, nun ... das ist nicht mehr so ​​gruselig frustrierend :)

Hier ist eine Geige wo du sehen kannst, was ich meine.

43
David Meister

Vor kurzem bin ich auf die besondere Situation gestoßen, dass ich eine setTimeout in einer loop verwenden musste. Wenn Sie dies verstehen, können Sie verstehen, wie Parameter an setTimeout übergeben werden.

Methode 1

Verwenden Sie forEach und Object.keys gemäß Sukimas Vorschlag :

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

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

Ich empfehle diese Methode.

Methode 2

Verwenden Sie 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/

Methode 3

Wenn Sie forEach oder bind nicht verwenden können, verwenden Sie ein IIFE :

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

Methode 4

Wenn Sie sich jedoch nicht für IE <10 interessieren, können Sie Fabios Vorschlag verwenden:

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

Methode 5 (ES6)

Verwenden Sie eine Variable mit Blockumfang:

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

Ich würde trotzdem empfehlen, Object.keys mit forEach in ES6 zu verwenden.

36
David Sherret

Hobblin hat diese Frage bereits kommentiert, aber es sollte wirklich eine Antwort sein!

Die Verwendung von Function.prototype.bind() ist der sauberste und flexibelste Weg, dies zu tun (mit dem zusätzlichen Vorteil, den Kontext this einstellen zu können):

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

Weitere Informationen finden Sie unter diesen MDN-Links:
https://developer.mozilla.org/de/docs/DOM/window.setTimeout#highlighter_547041https://developer.mozilla.org/docs/JavaScript/Reference/Global_Objects/Funktion/bind # With_setTimeout

22
dain

Einige Antworten sind korrekt, aber kompliziert.

Ich beantworte das noch einmal 4 Jahre später, weil ich immer noch zu komplexen Code finde, um genau diese Frage zu lösen. Dort IS eine elegante Lösung.

Übergeben Sie vor dem Aufruf von setTimeout keine Zeichenfolge als ersten Parameter, da dadurch effektiv ein Aufruf der langsamen "eval" -Funktion aufgerufen wird.

Wie übergeben wir also einen Parameter an eine Timeout-Funktion? Mit Verschluss:

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

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

Einige haben vorgeschlagen, beim Aufruf der Timeout-Funktion eine anonyme Funktion zu verwenden:

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

Die Syntax klappt. Zu dem Zeitpunkt, zu dem die Settopic aufgerufen wird, d. H. 4 Sekunden später, ist das XHR-Objekt möglicherweise nicht dasselbe. Daher ist es wichtig, dass Sie die Variablen vorbinden .

14
Schien

Ersetzen 

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

mit

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

oder besser noch, ersetzen Sie den String-Ausdruck durch eine anonyme Funktion

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

BEARBEITEN:

Der Kommentar von Brownstone ist falsch. Dies funktioniert wie beabsichtigt, wie dies in der Firebug-Konsole gezeigt wird

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

Beachten Sie, dass ich mit anderen einverstanden bin, dass Sie es vermeiden sollten, einen String an setTimeout zu übergeben, da dies eval() für den String aufruft und stattdessen eine Funktion übergeben wird.

9
Russ Cam

Meine Antwort:

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

Erläuterung:

Die erstellte anonyme Funktion gibt eine andere anonyme Funktion zurück. Diese Funktion hat Zugriff auf die ursprünglich übergebene topicId, so dass kein Fehler auftritt. Die erste anonyme Funktion wird sofort aufgerufen, wobei topicId übergeben wird, sodass die registrierte Funktion mit Verzögerung auf topicId zum Zeitpunkt des Aufrufs über Closures zugreifen kann.

OR

Dies konvertiert im Wesentlichen in:

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

EDIT: Ich habe dieselbe Antwort gesehen, also schau dir seine an. Aber ich habe seine Antwort nicht gestohlen! Ich habe einfach vergessen zu schauen. Lesen Sie die Erklärung und sehen Sie, ob es hilfreich ist, den Code zu verstehen.

9
user4447514

Die einfachste Cross-Browser-Lösung zur Unterstützung von Parametern in setTimeout:

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

Wenn Sie nichts dagegen haben, IE 9 und niedriger nicht zu unterstützen:

setTimeout(postinsql, 4000, topicId);

setTimeout desktop browser compatibility

setTimeout mobile browser compatibility

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

5

Ich weiß, dass es alt ist, aber ich wollte mein (bevorzugtes) Aroma dazu hinzufügen.

Ich denke, ein ziemlich lesbarer Weg, um dies zu erreichen, besteht darin, die topicId an eine Funktion zu übergeben, die wiederum das Argument verwendet, um die Themen-ID intern zu referenzieren. Dieser Wert ändert sich nicht, auch wenn topicId im Außenbereich kurz danach geändert wird.

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

oder kurz:

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

das funktioniert in allen Browsern (IE ist ein Oddball)

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

Die Antwort von David Meister scheint sich um Parameter zu kümmern, die sich unmittelbar nach dem Aufruf von setTimeout () ändern können, aber bevor die anonyme Funktion aufgerufen wird. Aber es ist zu umständlich und nicht sehr offensichtlich. Ich habe eine elegante Methode entdeckt, mit IIFE (sofort inviced function expression) dasselbe zu tun.

Im folgenden Beispiel wird die Variable currentList an die IIFE übergeben, die sie in ihrer Schließung speichert, bis die verzögerte Funktion aufgerufen wird. Selbst wenn sich die Variable currentList unmittelbar nach dem angezeigten Code ändert, wird setInterval() das Richtige tun.

Ohne diese IIFE-Technik wird die setTimeout()-Funktion definitiv für jedes h2-Element im DOM aufgerufen, aber bei allen diesen Aufrufen wird nur der Textwert des last h2-Elements angezeigt.

<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>
3
Gurjeet Singh

Wie habe ich diese Etappe gelöst?

genau so :

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

setTimeout warte einen Verweis auf eine Funktion, also habe ich sie in einer Schließung erstellt, die meine Daten interpretiert und eine Funktion mit einer guten Instanz meiner Daten zurückgibt!

Vielleicht können Sie diesen Teil verbessern:

_deepFunction(_deepData);

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

Ich habe es auf Chrome, Firefox und IE getestet und funktioniert gut. Ich weiß nicht, was Leistung angeht, aber ich brauchte es, um funktionieren zu können.

ein Beispieltest: 

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

Vielleicht können Sie die Signatur ändern, um sie komfortabler zu gestalten:

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

Und zum Schluss noch die ursprüngliche Frage beantworten:

 myNass_setTimeOut( postinsql, 4000, topicId );

Hoffe es kann helfen! 

ps: sorry aber englisch es ist nicht meine muttersprache!

2
Anonymous0day

Beachten Sie, dass der Grund von topicId in der Fehlermeldung "nicht definiert" war, dass sie als lokale Variable vorhanden war, als setTimeout ausgeführt wurde, nicht jedoch, wenn der verzögerte Aufruf von postinsql erfolgte. Die variable Lebensdauer ist besonders wichtig, insbesondere wenn Sie versuchen, "this" als Objektreferenz zu verwenden.

Ich habe gehört, dass Sie topicId als dritten Parameter an die Funktion setTimeout übergeben können. Es werden nicht viele Details angegeben, aber ich habe genügend Informationen erhalten, damit es funktioniert, und es ist in Safari erfolgreich. Ich weiß nicht, was sie mit dem "Millisekunden-Fehler" meinen. Schau es dir hier an:

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

2
billy

wenn Sie eine Variable als Parameter übergeben möchten, versuchen Sie dies

wenn die Anforderung Funktion und Var als Parmas ist, dann versuchen Sie dies

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

wenn nur Variablen als Parameter erforderlich sind, versuchen Sie dies

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

Sie können dies mit ES5 und ES6 versuchen

2
mad Man

Wenn Sie eine Funktion als Rückruf mit bestimmten Parametern übergeben müssen, können Sie im Allgemeinen Funktionen höherer Ordnung verwenden. Das ist mit ES6 ziemlich elegant:

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

setTimeout(someFunction(params), 1000);

Oder wenn someFunction erste Ordnung ist:

setTimeout(() => someFunction(params), 1000); 
1
John Hartman

Sie können die Standardfunktionalität von 'apply ()' ausprobieren. Sie können mehr Argumente als Anforderung im Array übergeben 

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

// Dies sind drei sehr einfache und prägnante Antworten:

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');
0
Rich

Da bei dem dritten optonalen Parameter in IE ein Problem auftritt und die Verwendung von closures verhindert, dass wir die Variablen ändern (beispielsweise in einer Schleife) und immer noch das gewünschte Ergebnis erzielen, schlage ich die folgende Lösung vor.

Wir können versuchen, Rekursion wie folgt zu verwenden:

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

Wir müssen sicherstellen, dass diese Variablen durch nichts anderes geändert werden und dass eine korrekte Rekursionsbedingung geschrieben wird, um eine unendliche Rekursion zu vermeiden.

Sie können den Parameter an die Rückruffunktion setTimeout übergeben als:

setTimeout (Funktion, Millisekunden, param1, param2, ...)

z.B.

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

function alertMsg(message) {
    alert(message)
}
0
Jatin Verma

@Jiri Vetyska Danke für den Beitrag, aber in deinem Beispiel ist etwas nicht in Ordnung ... Ich musste das Ziel, das herausgeschwenkt wird, an eine Zeitüberschreitungsfunktion übergeben und ich habe versucht, es zu versuchen. In IE9 getestet - funktioniert nicht. Ich habe auch etwas recherchiert und es scheint, als sei der dritte Parameter hier die verwendete Skriptsprache. Keine Erwähnung weiterer Parameter.

Also folgte ich der Antwort von @ meder und löste mein Problem mit diesem 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
}

Hoffe, das ist nützlich für jemanden.

0
Vladislav