2008-11-24 3 views
19

Каков наиболее рекомендуемый/лучший способ остановить создание нескольких экземпляров функции setTimeout (в javascript)?Как вы обрабатываете несколько экземпляров setTimeout()?

Пример (псевдо-код):

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

Моя проблема заключается в том, что если пользователь щелкает мышью несколько раз, у меня есть несколько экземпляров moveDiv() вызывался.

Опция, которую я видел, заключается в создании флага, который позволяет только вызывать таймаут, если другой экземпляр недоступен ... это лучший способ пойти?

Я надеюсь, что проясняет ....

ответ

21

при вызове SetTimeout, он возвращает вам переменную "ручкой" (число, я думаю)

, если вы звоните SetTimeout во второй раз, вы должны сначала

clearTimeout(handle) 

затем:

handle = setTimeout(...) 

, чтобы помочь автоматизировать этот процесс, вы можете использовать оболочку, которая связывает таймаут вызовы со строкой (Т.е. id div или все, что вы хотите), так что, если есть предыдущее определение с той же «строкой», оно автоматически очищается для вас, прежде чем устанавливать его снова,

Вы должны использовать массив (то есть словарь/хэш-карту) связать строки с помощью ручек.

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

Есть, конечно, и другие способы сделать это ..

+0

Ух, на самом деле, ваш код действительно не подавляет несколько «потоков» таймаута. (Обратите внимание, как тайм-аут в вопросе рекурсивный.) Больше необходимо. ;) – 2008-11-24 19:28:29

+0

Во всяком случае, это была очень полезная логика, спасибо – 2017-06-01 13:04:50

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

Этот ответ не решает проблему, указанную в вопросе. – 2008-11-24 19:15:38

1

Вы можете хранить несколько флагов в перекодировки-таблицы (хэш), используя objID в качестве ключа.

var moving = {}; 

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

Вы всегда можете перезаписать кнопки onclick для возврата false. Пример:

<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

Вы можете установить глобальный флаг где-то (как вар mouseMoveActive = false;), что говорит вам, есть ли у Вас уже во время разговора, и если да не запускать следующий. Вы устанавливаете флаг непосредственно перед тем, как вводить вызов setTimeout, после проверки того, установлен ли он уже. Затем в конце процедуры, вызванной в setTimeout(), вы можете сбросить флаг.

2

Я хотел бы сделать это следующим образом:

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

Я не проверял все это, и просто сократить это в редакторе здесь. Может работать, может и нет, надеюсь, будет пищей для размышлений.

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

Последовательные вызовы с тем же идентификатором отменит предыдущий вызов.

1

Вы можете избежать глобальной или меньшей переменной, используя свойство внутри функции. Это хорошо работает, если функция используется только для этого конкретного контекста.

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

Я использую это, чтобы заставить сборку мусора на все устаревшие ссылки таймаута, который на самом деле не-лаг моего сценария Палатки:

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

Моего оригинальный неаккуратно код был генерирующим массивным массив глубоко 100,000 за очень короткое время, но это действительно трюк!

Смежные вопросы