2009-01-02 33 views
1

我使用下面的代碼在Javascript中創建倒計時。 n是重複次數,freq是執行前等待的毫秒數,funN是每次迭代調用的函數(通常是更新DOM的一部分的函數),funDone是倒數時調用的函數做完了。事件發生n次的最佳方式?

function timer(n, freq, funN, funDone) 
{ 
    if(n == 0){ 
     funDone(); 
    }else{ 
     setTimeout(function(){funN(n-1); timer(n-1, freq, funN, funDone);}, freq);  
    } 
} 

它可以被稱爲像這樣:

timer(10, 
     1000, /* 1 second */ 
     function(n){console.log("(A) Counting: "+n);}, 
     function() {console.log("(A) Done!");} 
    ); 

    timer(10, 
     500, 
     function(n){console.log("(B) Counting: "+n);}, 
     function() {console.log("(B) Done!");} 
    ); 

這樣做的好處是,我可以調用計時器(),因爲我想盡可能多的時間,而不必擔心全局變量等是否有更好的如何做到這一點?是否有一個乾淨的方法來使setInterval在一定次數的調用之後停止(不使用全局變量)?這段代碼還創建了一個新的lambda函數,每次調用setTimeout時,似乎它可能會對大倒計數產生問題(我不確定JavaScript的垃圾收集器如何處理這個問題)。

有沒有更好的方法來做到這一點?謝謝。

+0

這可能是一個好主意,問問題並用自己的方法回答。作爲練習剩下的onComplete回調函數 – Artelius 2009-01-02 04:59:07

回答

2

我想創建接收計數器和一個接收函數指針執行一個對象,一個類似於下面的僞代碼:

TimedIteration = function(interval, iterations, methodToRun, completedMethod){ 

    var counter = iterations; 
    var timerElapsed = methodToRun; //Link to timedMethod() method 
    var completed = callbackMethod; 

    onTimerElapsed = function(){ 
    if (timerElapsed != null) 
     timerElapsed(); 
    } 

    onComplete = function(){ 
    if (completed != null) 
     completed(); 
    } 

    timedMethod = function(){ 
    if (counter != null) 
     if (counter > 0) { 
     setTimeOut(interval, onTimerElapsed); 
     counter--; 
     } 
     else 
     onComplete(); 
     this = null; 
    } 
    } 

    if ((counter != null)&&(counter > 0)){ 
    //Trip the initial iteration... 
    setTimeOut(interval, timedMethod); 
    counter--; 
    } 
} 

顯然,這是僞代碼,我沒有測試它一個IDE和語法上我不確定它是否會像現在這樣工作[如果它真的讓我感到驚訝],但基本上你在做什麼是創建一個包裝對象,它接收一個時間間隔,一個數字迭代的方法以及在計時器運行時運行的方法。

你會再調用這個對你的方法,像這樣運行:

function myMethod(){ 
    doSomething(); 
} 

function doWhenComplete(){ 
    doSomethingElse(); 
} 

new TimedIteration(1000, 10, myMethod, doWhenComplete); 
4

這基本上是相同的思路@balabaster,但它進行了測試,使用的原型,並具有更靈活一點接口。

var CountDownTimer = function(callback,n,interval) { 
    this.initialize(callback,n,interval); 
} 

CountDownTimer.prototype = { 
    _times : 0, 
    _interval: 1000, 
    _callback: null, 
    constructor: CountDownTimer, 
    initialize: function(callback,n,interval) { 
        this._callback = callback; 
        this.setTimes(n); 
        this.setInterval(interval); 
       }, 
    setTimes: function(n) { 
        if (n) 
         this._times = n 
        else 
         this._times = 0; 
       }, 
    setInterval: function(interval) { 
        if (interval) 
         this._interval = interval 
        else 
         this._interval = 1000; 
       }, 
    start: function() { 
        this._handleExpiration(this,this._times); 
       }, 
    _handleExpiration: function(timer,counter) { 
        if (counter > 0) { 
         if (timer._callback) timer._callback(counter); 

         setTimeout(function() { 
              timer._handleExpiration(timer,counter-1); 
              }, 
              timer._interval 
            ); 
        } 
       } 
}; 

var timer = new CountDownTimer(function(i) { alert(i); },10); 

... 

<input type='button' value='Start Timer' onclick='timer.start();' /> 
+0

。 :-) – tvanfosson 2009-01-02 05:31:51

2

我喜歡你原來的解決方案比提出的替代方案好,所以我就改成了不創建一個新的功能,每次迭代(和fun()的論據已經遞減,前值 - 如果需要改變.. )

function timer(n, delay, fun, callback) { 
    setTimeout(
     function() { 
      fun(n); 
      if(n-- > 0) setTimeout(arguments.callee, delay); 
      else if(callback) callback(); 
     }, 
     delay); 
} 
+0

考慮到setTimeout的限制(即它只能使用函數而不是對象,沒有參數),這更加實用。考慮添加一個「範圍」和「參數」參數以將該函數應用於對象,併爲其提供參數。 – 2009-01-02 13:55:01