Come gestisci più istanze di setTimeout ()?

Qual è il modo più consigliato / migliore per impedire la creazione di più istanze di una funzione setTimeout (in javascript)?

Un esempio (codice psuedo):

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

Il mio problema è che se l’utente fa clic con il mouse più volte, ho più istanze di moveDiv () chiamata.

L’opzione che ho visto è quella di creare un flag, che consente di chiamare il timeout solo se non sono disponibili altre istanze … è il modo migliore per andare?

Spero che lo chiarisca ….

quando chiami settimeout, ti restituisce una variabile “handle” (un numero, penso)

se chiami settimeout una seconda volta, dovresti prima

 clearTimeout( handle ) 

poi:

 handle = setTimeout( ... ) 

per aiutare ad automatizzare questo, potresti usare un wrapper che associa le chiamate di timeout a una stringa (cioè l’ID del div o qualsiasi cosa tu voglia), in modo che se c’è un settimeout precedente con la stessa “stringa”, lo cancella automaticamente prima impostandolo di nuovo,

Dovresti usare una matrice (es. Dizionario / hashmap) per associare le stringhe con le maniglie.

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

Ci sono naturalmente altri modi per farlo ..

Non ho provato nulla di tutto ciò e l’ho appena tagliato nell’editor qui. Potrebbe funzionare, potrebbe non, si spera che sarà spunti di riflessione però.

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

Le chiamate successive con lo stesso identificatore annulleranno la chiamata precedente.

Lo farei in questo modo:

 // 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"]); 

È ansible memorizzare più flag in una tabella di ricerca (hash) usando objID come chiave.

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

È ansible evitare una variabile globale o inferiore utilizzando una proprietà all’interno della funzione. Funziona bene se la funzione viene utilizzata solo per questo specifico contesto.

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

puoi sempre sovrascrivere i pulsanti onclick per restituire false. esempio:

   Javascript example    

Javascript example

Should Only Fire Once

Puoi impostare un flag globale da qualche parte (come var mouseMoveActive = false;) che ti dice se sei già in una chiamata e se non lo fai avvia quello successivo. Si imposta la bandiera appena prima di entrare nella chiamata setTimeout, dopo aver controllato se è già impostata. Quindi alla fine della routine chiamata in setTimeout () puoi resettare il flag.

Lo sto usando per forzare una garbage collection su tutti i riferimenti timeout obsoleti che non hanno rallentato la mia performance di script:

 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 

Il mio codice sciatto originale stava generando un enorme array 100.000+ in profondità in un tempo molto breve, ma questo ha davvero funzionato!