2008-11-24 19 views
19

Was ist der empfohlene/beste Weg, um das Erstellen mehrerer Instanzen einer setTimeout-Funktion zu verhindern (in Javascript)?Wie behandeln Sie mehrere Instanzen von setTimeout()?

Ein Beispiel (Pseudo-Code):

function mouseClick() 
{ 
    moveDiv("div_0001", mouseX, mouseY); 
} 

function moveDiv(objID, destX, destY) 
{ 
    //some code that moves the div closer to destination 
    ... 
    ... 
    ... 

    setTimeout("moveDiv(objID, destX, destY)", 1000); 
    ... 
    ... 
    ... 
} 

Mein Problem ist, dass, wenn der Benutzer die Maus mehrmals klickt, ich mehrere Instanzen von moveDiv() haben immer genannt.

Die Option, die ich gesehen habe, ist ein Flag zu erstellen, das nur erlaubt, das Timeout aufzurufen, wenn keine andere Instanz verfügbar ist ... ist das der beste Weg zu gehen?

Ich hoffe, dass es deutlich macht ....

Antwort

21

wenn Sie SetTimeout nennen, es gibt eine Variable "Handle" (eine Zahl, glaube ich)

wenn Sie SetTimeout ein zweites Mal anrufen, sollten Sie zuerst

clearTimeout(handle) 

dann:

handle = setTimeout(...) 

dies zu automatisieren, können Sie einen Wrapper verwenden, die Mitarbeiter Anrufe mit einem String-Timeout (d.h. die id des divs, oder irgendetwas, das Sie wollen), so dass es, wenn es ein vorheriges settimeout mit dem gleichen "string" gibt, es für Sie automatisch löscht, bevor Sie es wieder setzen,

Sie würden ein Array (dh Dictionary/hashmap) verwenden Verknüpfen von Zeichenfolgen mit Handles.

var timeout_handles = []  
function set_time_out(id, code, time) /// wrapper 
{ 
    if(id in timeout_handles) 
    { 
     clearTimeout(timeout_handles[id]) 
    } 

    timeout_handles[id] = setTimeout(code, time) 
} 

Es gibt natürlich auch andere Möglichkeiten, dies zu tun ..

+0

Uhm, tatsächlich unterdrückt Ihr Code nicht wirklich mehrere Timeout "Threads". (Beachten Sie, dass das Zeitlimit in der Frage rekursiv ist.) Es wird mehr benötigt. ;) –

+0

Wie auch immer, es war sehr hilfreich Logik, danke –

0
var timeout1 = window.setTimeout('doSomething();', 1000); 
var timeout2 = window.setTimeout('doSomething();', 1000); 
var timeout3 = window.setTimeout('doSomething();', 1000); 

// to cancel: 
window.clearTimeout(timeout1); 
window.clearTimeout(timeout2); 
window.clearTimeout(timeout3); 
+1

Diese Antwort behandelt das in der Frage angegebene Problem nicht. –

1

Sie mehrere Flags in einer Lookup-Tabelle (Hash) speichern könnte objID als Schlüssel.

var moving = {}; 

function mouseClick() 
{ 
    var objID = "div_0001"; 
    if (!moving[objID]) 
    { 
    moving[objID] = true; 
    moveDiv("div_0001", mouseX, mouseY); 
    } 
} 
0

Sie können die Schaltflächen onclick immer überschreiben, um false zurückzugeben. Beispiel:

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="UTF-8"> 
<head> 
    <title>Javascript example</title> 
    <script type="text/javascript">   
     var count = 0; 
     function annoy() { 
      document.getElementById('testa').onclick = function() { return false; }; 

      setTimeout(function() { 
       alert('isn\'t this annoying? ' + count++); 
       document.getElementById('testa').onclick = window.annoy; 
      }, 1000); 

     } 
    </script> 
</head> 
<body> 
    <h2>Javascript example</h2> 
    <a href="#" onClick="annoy()" id="testa">Should Only Fire Once</a><br /> 
</body> 
</html> 
0

Sie eine globale Flagge irgendwo einstellen können (wie var mouseMoveActive = false;), der Ihnen sagt, ob Sie bereits in einem Gespräch sind, und wenn ja fange nicht mit dem nächsten an. Sie setzen das Flag, bevor Sie den setTimeout-Aufruf eingeben, nachdem Sie überprüft haben, ob es bereits festgelegt ist. Dann können Sie am Ende der in setTimeout() aufgerufenen Routine das Flag zurücksetzen.

2

Ich würde es auf diese Weise tun:

// declare an array for all the timeOuts 
var timeOuts = new Array(); 

// then instead of a normal timeOut call do this 
timeOuts["uniqueId"] = setTimeout('whateverYouDo("fooValue")', 1000); 

// to clear them all, just call this 
function clearTimeouts() { 
    for (key in timeOuts) { 
    clearTimeout(timeOuts[key]); 
    } 
} 

// clear just one of the timeOuts this way 
clearTimeout(timeOuts["uniqueId"]); 
+0

Dies ist eine gute Lösung. Ich schätze –

+0

verstehe ich es richtig? Jedes Mal, wenn Sie 'setTimeout' aufrufen, überschreiben Sie den Wert in Ihrem (einzigen) Array-Element' timeOuts ["uniqueId"] ', also bedeutet es, dass das Array in der Funktion' clearTimeouts() 'nicht das tut, was Sie erwarten ... – Enriqe

+0

'setTimeout()' sollte nicht mit einer Zeichenfolge als der erste Parameter aufgerufen werden - es sollte eine Funktionsreferenz oder eine anonyme Funktion, aber keine Zeichenfolge sein. Eine Zeichenfolge wirkt sich auf den Bereich aus, in dem die Funktion ausgeführt wird. –

2

ich irgendetwas davon nicht getestet haben, und dies gerade hier im Editor zerschneiden. Könnte funktionieren, vielleicht nicht, aber hoffentlich wird es Denkanstöße geben.

var Timeout = { 
    _timeouts: {}, 
    set: function(name, func, time){ 
    this.clear(name); 
    this._timeouts[name] = {pending: true, func: func}; 
    var tobj = this._timeouts[name]; 
    tobj.timeout = setTimeout(function() 
    { 
/* setTimeout normally passes an accuracy report on some browsers, this just forwards that. */ 
     tobj.func.call(arguments); 
     tobj.pending = false; 
    }, time); 
    }, 
    hasRun: function(name) 
    { 
     if(this._timeouts[name]) 
     { 
      return !this._timeouts[name].pending; 
     } 
     return -1; /* Whut? */ 
    }, 
    runNow: function(name) 
    { 
     if(this._timeouts[name] && this.hasRun(name)===false) 
     { 
     this._timeouts[name].func(-1); /* fake time. *shrug* */ 
     this.clear(name); 
     } 
    } 
    clear: function(name) 
    { 
    if(this._timeouts[name] && this._timeouts[name].pending) 
    { 
     clearTimeout(this._timeouts[name].timeout); 
     this._timeouts[name].pending = false; 
    } 
    } 
}; 

Timeout.set("doom1", function(){ 
    if( Timeout.hasRun("doom2") === true) 
    { 
    alert("OMG, it has teh run"); 
    } 
}, 2000); 
Timeout.set("doom2", function(){ 
    /* NooP! */ 
}, 1000); 

Aufeinanderfolgende Anrufe mit demselben Bezeichner heben den vorherigen Anruf auf.

1

Sie können eine globale oder kleinere Variable vermeiden, indem Sie eine Eigenschaft innerhalb der Funktion verwenden. Dies funktioniert gut, wenn die Funktion nur für diesen spezifischen Kontext verwendet wird.

function set_time_out(id, code, time) /// wrapper 
{ 
    if(typeof this.timeout_handles == 'undefined') this.timeout_handles = []; 

     if(id in this.timeout_handles) 
     { 
       clearTimeout(this.timeout_handles[id]) 
     } 

     this.timeout_handles[id] = setTimeout(code, time) 
} 
0

ich dies mit allen veralteten Timeout Referenzen eine Garbage Collection zu erzwingen, die wirklich mein Skript preformance un-Lag:

var TopObjList = new Array(); 
function ColorCycle(theId, theIndex, RefPoint) { 
    ... 
    ... 
    ... 
    TopObjList.push(setTimeout(function() { ColorCycle(theId, theIndex ,CCr); },CC_speed)); 
    TO_l = TopObjList.length; 
    if (TO_l > 8888) { 
     for (CCl=4777; CCl<TO_l; CCl++) { 
      clearTimeout(TopObjList.shift()); 
      } 
     } 
    } 

Mein ursprünglicher schlampig Code wurde eine massive Array zu erzeugen 100,000 tief in sehr kurzer Zeit, aber das hat wirklich den Trick!