0

我正在开发一个相当大的应用程序,我需要在按下某个键时以特定间隔再次调用一个函数。应用程序的某些部分我无法编辑,但它正在替换我的 .onkeyup() 侦听器,有时间隔会永远留在那里。我真正想要的是当对象被销毁、重新分配等时间隔停止......在 setInterval()、绑定、闭包之后,我做了这个来尝试一些东西,现在我更加困惑:

function myInterval(){
    this.name = 'Paul'
    that=this;
this.go = function go(){
        if(that){
            this.interval = setTimeout(function(){
                console.log(that.name);
                that.go();
            },100);
        };
        console.log(that.name);
    };
};

periodic = new myInterval();
periodic.go();
setTimeout(function(){
    periodic.name='George';
}, 200);
setTimeout(function(){
    periodic.name ='John';
    periodic.go = '';
    periodic.name = 'Ringo'
}, 300);

输出:

Paul
Paul
Paul
George
George
Ringo 
> Uncaught TypeError: Property 'go' of object #<myInterval> is not a function

所以,重新分配功能是可行的,但如果我更换

periodic.go = '';

periodic = '';

我明白了

Paul
Paul
Paul
George
George
John
John
...

等等永远;间隔永远不会停止...

  1. 谁能解释一下?

  2. 是否有一个通用的、优雅的解决方案来确保我不会将跑步间隔丢到以太中?

4

3 回答 3

3
var timer = setTimeout(func,100)

清除它

if(timer)
clearTimeout(timer)

在间隔的情况下

var timer = setInterval(func,100)

清除它

if(timer)
clearInterval(timer)

前任

function myInterval(){
    this.name = 'Paul'
    that=this;

    this.go = function go(){
        if(that){
            this.interval = setTimeout(function(){
                console.log(that.name);
                that.go();
            },100);
        };
        console.log(that.name);
    };

    this.stop = function(){ if(this.interval) clearInterval(this.interval);};
};
于 2013-11-14T05:46:43.870 回答
1

在您的代码中:

function myInterval(){
    this.name = 'Paul'
    that=this;

当你第一次调用myInterval并执行上面的行时,它变成了一个全局的,我认为你的意思是让它保持在本地。否则,将引用最后创建的实例,它不一定是“当前”实例。

无论如何,最好的方法是给实例一个停止方法。所以你也是:

// By convention, constructors start with a capital letter
function MyInterval() {

    // Use a more suitable name than "that" to reference the instance
    var interval = this;
    this.name = 'Paul'

    // This keeps calling itself every 100ms
    this.go = function go(){

      // Keep a reference to the timeout so it can be cancelled
      this.timeout = setTimeout(function(){
                       console.log('setTimeout: ' + interval.name);
                       interval.go();
                     }, 100);
      console.log('Go: ' + interval.name);
    };

    // Stop the timeout
    this.stop = function() {  
      if (interval.timeout) {
        clearTimeout(interval.timeout);
      }
    };
};

var periodic = new MyInterval();

// In 100 ms, it will log its name
periodic.go();

// In 200 ms its name will be changed
setTimeout(function(){
    periodic.name='George';
}, 200);

// In 500 ms its name will be changed and it will be cancelled.
setTimeout(function(){
    periodic.name ='John';

    // call stop here
    periodic.stop();
    periodic.name = 'Ringo'
}, 500);
于 2013-11-14T06:16:48.943 回答
1

间隔永远不会停止......谁能解释一下?

被困在闭包范围内的变量是其原因,以下代码将在将 o 设置为 null 的同一范围内使用变量 o。

注意:我更喜欢使用闭包创建者来限制范围并防止其他意外。以下将在运行时创建闭包以保持代码简单。

var o = {};
setTimeout(function(){//closure accessing o directly
   console.log("why is o null here:",o);
},100);
o=null;

以下代码将使用 o 作为传递的 o,传递的 o 现在被困在创建的闭包范围内,并且将 o 设置为 null 不会影响传递的 o。变异 o (o.something=22) 会影响传递的 o。(谷歌“javascript by reference by value”供参考)

var o = {};
setTimeout((function(o){
  return function(){//closure accessing passed o
   console.log("why is o not here:",o);
  };
}(o)),100);
o=null;

要解决循环中创建闭包的常见问题,请将变量 (i) 传递给返回闭包的函数

for(var i = 0;i<10;i++){
  setTimeout((function(i){
    return function(){//not using i in the for loop but the passed one
     console.log("and i is:",i);//0 to 9
    };
  }(i)),100);
}

因为将 i 变量与闭包在同一范围内会给您带来不想要的结果:

for(var i = 0;i<10;i++){
  setTimeout(function(){
    console.log("and i is:",i);//10 times and i is: 10
  },100);
}

为什么periodic.go="" 起作用与通过引用传递值有关。下面的代码显示了它是如何工作的:

function test(o){
  o=22;//no mutation but an assignment
}
var o = {name:"me"};
test(o);
console.log(o);//Object { name="me" }

function test2(o){
  o.name="you";//mutates
}
test2(o);
console.log(o);//Object { name="you"}

怎么解决

我已经稍微更改了您的代码,以利用共享成员的原型(go 函数)并创建闭包以确保闭包的范围仅限于您实际需要的范围。

有关更多详细信息,请阅读构造函数和 this 变量的介绍

function MyInterval(){//capitalize constructor
    this.name = 'Paul';
    this.doContinue = true;
    this.timeoutid = false;
};
MyInterval.prototype.closures ={//creates closures with limited scope
  //closure for the go function setting the invoking object
  go:function(me){
    return function(){
      console.log("In go, name is:",me.name);
      me.go();
      //de reference "me", we no longer need it
      // can't do this in a setInterval though
      me=null;
    };
  }
}
MyInterval.prototype.go = function(){
  if(this.constructor===MyInterval){
    //if you were to call go multiple times
    if(this.timeoutid)
      clearTimeout(this.timeoutid);
    //do it again if this.doContinue is true
    this.timeoutid = (this.doContinue)? setTimeout(
      this.closures.go(this)
      //creates a closure function
      ,100
    ):false;
    return;
  };
  console.log("this is not the correct value:",this);
};
//added stop, good call from shadow, now you can stop immediately
//  or set doContinue to false and let it run it's course
MyInterval.prototype.stop = function(){
  if(this.timeoutid)
    clearTimeout(this.timeoutid);
  this.timeoutid=false;
};

periodic = new MyInterval();
periodic.go();
//because the clearTimeout you can accedentally do something silly like:
periodic.go();
periodic.go();
setTimeout(function(){
    periodic.name='George';
}, 150);
setTimeout(function(){
    periodic.name ='John';
    periodic.doContinue = false;
    periodic.name = 'Ringo'
}, 250);
于 2013-11-14T06:03:50.527 回答