2008-11-24 14 views
19

¿Cuál es la mejor/la mejor manera de evitar que se creen varias instancias de una función setTimeout (en javascript)?¿Cómo se manejan varias instancias de setTimeout()?

Un ejemplo (pseudo código):

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

Mi problema es que si el usuario hace clic en el ratón varias veces, tengo varias instancias de moveDiv() recibiendo llamadas.

La opción que he visto es crear un indicador, que solo permite llamar al tiempo de espera si no hay otra instancia disponible ... ¿es la mejor manera de hacerlo?

espero que deja claro ....

Respuesta

21

cuando se llama a setTimeout, le devuelve un "mango" variable (un número, creo)

si se llama a setTimeout una segunda vez, primero debe

clearTimeout(handle) 

a continuación:

handle = setTimeout(...) 

para ayudar a automatizar esto, se podría utilizar un envoltorio que los asociados de tiempo de espera de llamadas con una cadena (es decir la identificación del div, o cualquier cosa que desee), de modo que si hay un settimeout anterior con la misma "cadena", se borra automáticamente antes de volver a configurarlo,

Utilizaría una matriz (es decir, diccionario/hashmap) para asociar cadenas con controladores.

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

Por supuesto, hay otras maneras de hacer esto ..

+0

Uhm, en realidad, su código realmente no suprime múltiples "subprocesos" de tiempo de espera. (Tenga en cuenta que el tiempo de espera en la pregunta es recursivo). Se necesita más. ;) –

+0

De todos modos, fue una lógica muy útil, gracias –

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

Esta respuesta no resuelve el problema planteado en la pregunta. –

1

podría almacenar múltiples banderas en una tabla de consulta (hash) utilizando objID como clave.

var moving = {}; 

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

siempre puede sobrescribir los botones de clic para devolver falso. ejemplo:

<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

se puede establecer un indicador global algún lugar (como var mouseMoveActive = false;) que le indica si usted ya está en una llamada y si es así no empieces el siguiente. Establece el indicador justo antes de ingresar a la llamada a setTimeout, después de verificar si ya está configurado. Luego, al final de la rutina llamada en setTimeout() puede restablecer el indicador.

2

lo haría de esta manera:

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

Esta es una buena solución. Agradezco –

+0

¿Lo entiendo correctamente? Cada vez que llamas a 'setTimeout' estás sobreescribiendo el valor en tu (único) elemento de matriz' timeOuts ["uniqueId"] 'por lo que significa que recorrer esa matriz en la función' clearTimeouts() 'no hará lo que esperas ... – Enriqe

+0

'setTimeout()' no se debe invocar con una cadena como primer parámetro; debe ser una referencia de función o una función anónima, pero no una cadena. Una cadena afectará el alcance en el que se ejecuta la función. –

2

No he probado nada de esto, y acaba de cortar esto en el editor de aquí. Podría funcionar, quizás no, con suerte será algo para pensar.

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

Las llamadas sucesivas con el mismo identificador cancelarán la llamada anterior.

1

Puede evitar una variable global o inferior mediante el uso de una propiedad dentro de la función. Esto funciona bien si la función solo se usa para este contexto específico.

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

estoy usando esto para forzar una recolección de basura en todas las referencias de tiempo de espera obsoletos que realmente ONU-lag mi Preformance guión:

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

Mi código descuidado original generando un enorme despliegue de 100.000 profunda en muy poco tiempo pero esto realmente funcionó!

Cuestiones relacionadas