Javascript 事件发生n次的最佳方式?

Javascript 事件发生n次的最佳方式?,javascript,Javascript,我使用以下代码在Javascript中创建倒计时。n是重复的次数,freq是执行前等待的毫秒数,funN是每次迭代时调用的函数(通常是更新部分DOM的函数),funDone是倒计时完成时调用的函数 function timer(n, freq, funN, funDone) { if(n == 0){ funDone(); }else{ setTimeout(function(){funN(n-1); timer(n-1, freq, funN,

我使用以下代码在Javascript中创建倒计时。n是重复的次数,freq是执行前等待的毫秒数,funN是每次迭代时调用的函数(通常是更新部分DOM的函数),funDone是倒计时完成时调用的函数

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!");}
     );
这样做的好处是,我可以任意多次调用timer(),而不用担心全局变量等。有更好的方法吗?有没有一种干净的方法可以让setInterval在一定数量的调用后停止(而不使用全局变量)?这段代码还通过每次调用setTimeout创建了一个新的lambda函数,这对于大的倒计时似乎是有问题的(我不确定javascript的垃圾收集器如何处理这个问题)


有更好的方法吗?谢谢。

我将创建一个对象,该对象接收计数器并接收要执行的函数指针,类似于以下伪代码:

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

我将创建一个对象,该对象接收计数器并接收要执行的函数指针,类似于以下伪代码:

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

这基本上与@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();' />
var CountDownTimer=函数(回调,n,间隔){
初始化(回调,n,间隔);
}
倒计时。原型={
_次数:0,,
_间隔时间:1000,
_回调:null,
构造函数:倒计时,
初始化:函数(回调,n,间隔){
这个._callback=callback;
这是设定时间(n);
这个.setInterval(interval);
},
设置时间:函数(n){
如果(n)
这个.\u次=n
其他的
这个._次=0;
},
设置间隔:函数(间隔){
如果(间隔)
这个时间间隔=时间间隔
其他的
这个时间间隔=1000;
},
开始:函数(){
这个.(这个,这个)次;;
},
_HandleExption:功能(计时器、计数器){
如果(计数器>0){
if(定时器._回调)定时器._回调(计数器);
setTimeout(函数(){
定时器。手柄膨胀(定时器,计数器-1);
},
时间间隔
);
}
}
};
var timer=新的倒计时(函数(i){alert(i);},10);
...

这基本上与@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();' />
var CountDownTimer=函数(回调,n,间隔){
初始化(回调,n,间隔);
}
倒计时。原型={
_次数:0,,
_间隔时间:1000,
_回调:null,
构造函数:倒计时,
初始化:函数(回调,n,间隔){
这个._callback=callback;
这是设定时间(n);
这个.setInterval(interval);
},
设置时间:函数(n){
如果(n)
这个.\u次=n
其他的
这个._次=0;
},
设置间隔:函数(间隔){
如果(间隔)
这个时间间隔=时间间隔
其他的
这个时间间隔=1000;
},
开始:函数(){
这个.(这个,这个)次;;
},
_HandleExption:功能(计时器、计数器){
如果(计数器>0){
if(定时器._回调)定时器._回调(计数器);
setTimeout(函数(){
定时器。手柄膨胀(定时器,计数器-1);
},
时间间隔
);
}
}
};
var timer=新的倒计时(函数(i){alert(i);},10);
...

我更喜欢您的原始解决方案,而不是建议的备选方案,因此我只是将其更改为不为每次迭代创建新函数(并且
fun()
的参数现在是减量之前的值-如果需要,请更改…)


我更喜欢您的原始解决方案,而不是建议的备选方案,因此我只是将其更改为不为每次迭代创建新函数(并且
fun()
的参数现在是减量前的值-如果需要,请更改…)


提问并用自己的方法回答可能是个好主意。提问并用自己的方法回答可能是个好主意。完成回调作为练习。:-)onComplete回调作为练习离开。:-)这是更实际的