首页 新闻 会员 周边 捐助

js 封装setInterval问题

0
悬赏园豆:10 [已解决问题] 解决于 2016-10-28 15:34

想显示导入文件进度,js实现了一个导入耗费时间的效果,但是想将其封装成面向对象的,可是封装之后没有正常运行,js 面向对象能力不够啊,不知道代码是啥原因,setinterval没有间隔时间运行,只运行了一次,请高手指导一下原因,谢谢啦!

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>新增属性值</title>
<script type="text/javascript" src="jquery-1.10.2.min.js"></script>
</head>
<body>
<div id="importInfo"></div>
<input type="button" onclick="inportProcesser.Start()" value="开始">
<input type="button" onclick="inportProcesser.Close()" value="结束">

<script>
  function Progresser(intervalms, intervalHandle) {
            this.intervalMs = intervalms;
            this. totalIntervalMs = 0;
            this. timer=null;
            this.Oninterval = intervalHandle;
            
        }

        Progresser.prototype = {

            constructor: Progresser,

            Start: function () {
                //console.log("Start totalIntervalMs:" + this.totalIntervalMs);
                this.timer = setInterval( this.IntervalHandle() , this.intervalMs);
                //console.log("Start timer:" + this.timer);
            },
            Close: function () {
                //console.log("Close totalIntervalMs:" + this.totalIntervalMs);
                if (this.timer != null) {
                    //console.log("Close timer:clearInterval pre" + this.timer);
                    clearInterval(this.timer);
                    //console.log("Close timer:clearInterval next" + this.timer);
                }
                this.totalIntervalMs = 0;
            }
            ,
            IntervalHandle: function () {
                 this.totalIntervalMs += this.intervalMs ;
                //console.log("IntervalHandle totalIntervalMs:" + this.totalIntervalMs);
                this.Oninterval(this.totalIntervalMs);
                //console.log("IntervalHandle timer:" + this.timer);
            }

        }
        var inportProcesser = new Progresser(500, importing2);
        
        function importing2(totalIntervalMs) {
            var second = (totalIntervalMs / 1000.0).toFixed(1);
            console.log("seconds:" + second + "s..");
        }

</script>
</body>
</html>
摆脱菜鸟的主页 摆脱菜鸟 | 初学一级 | 园豆:16
提问于:2016-10-28 14:07
< >
分享
最佳答案
0
Start: function () {
  //console.log("Start totalIntervalMs:" + this.totalIntervalMs);
  this.timer = setInterval( () => {
    this.IntervalHandle();
  }, this.intervalMs);
  //console.log("Start timer:" + this.timer);
},

这里改成这样就可以了

收获园豆:7
by.Genesis | 老鸟四级 |园豆:2824 | 2016-10-28 14:32

ok,没问题了,多谢!

如果能阐释一下原理的话,就完美了!!!

摆脱菜鸟 | 园豆:16 (初学一级) | 2016-10-28 15:29

@摆脱菜鸟:

setInterval 的第一个参数应该是个 function,所以这里

this.timer = setInterval( this.IntervalHandle() , this.intervalMs);

不应该带括号,带了括号这里就变成 this.IntervalHandle 函数的返回值了,就要写成这样:

this.timer = setInterval( this.IntervalHandle , this.intervalMs);

但是这样又会出现另外一个作用域的问题,setInterval 调用的函数内部 this 指向的是 window,

this.Oninterval(this.totalIntervalMs);

代码运行到这里就会报错,因为 window 对象上面没有 Oninterval 这个方法,代码我是用的箭头函数,改造成兼容 ES5 的就像这样:

Start: function () {
  //console.log("Start totalIntervalMs:" + this.totalIntervalMs);
  var self = this;
  this.timer = setInterval(function() {
    self.IntervalHandle();
  }, this.intervalMs);
  //console.log("Start timer:" + this.timer);
},

这样解释希望能明白?

by.Genesis | 园豆:2824 (老鸟四级) | 2016-10-28 15:38

@by.Genesis: 

上面的代码运行有问题了,啥原因?箭头函数方式firfox中运行没问题,但是ie中不能正常运行。

你改造后的代码,都不能运行了。

楼下兄弟的代码都能兼容运行,但是声明全局变量破坏了封装性啊,如何破?

摆脱菜鸟 | 园豆:16 (初学一级) | 2016-10-28 16:10

@摆脱菜鸟: 

箭头函数是ES6的写法,老浏览器不兼容,我修改后的代码我是经过测试了的没有问题啊

by.Genesis | 园豆:2824 (老鸟四级) | 2016-10-28 16:16

@by.Genesis: 

确实不能执行有问题啊,其他方法没改动吗?

摆脱菜鸟 | 园豆:16 (初学一级) | 2016-10-28 16:34

@摆脱菜鸟: 

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>新增属性值</title>
</head>
<body>
<div id="importInfo"></div>
<input type="button" onclick="inportProcesser.Start()" value="开始">
<input type="button" onclick="inportProcesser.Close()" value="结束">

<script>
  function Progresser(intervalms, intervalHandle) {
            this.intervalMs = intervalms;
            this. totalIntervalMs = 0;
            this. timer=null;
            this.Oninterval = intervalHandle;
            
        }

        Progresser.prototype = {

            constructor: Progresser,

            Start: function () {
                var self = this;
                //console.log("Start totalIntervalMs:" + this.totalIntervalMs);
                this.timer = setInterval( function() {
                    self.IntervalHandle();
                } , this.intervalMs);
                //console.log("Start timer:" + this.timer);
            },
            Close: function () {
                //console.log("Close totalIntervalMs:" + this.totalIntervalMs);
                if (this.timer != null) {
                    //console.log("Close timer:clearInterval pre" + this.timer);
                    clearInterval(this.timer);
                    //console.log("Close timer:clearInterval next" + this.timer);
                }
                this.totalIntervalMs = 0;
            }
            ,
            IntervalHandle: function () {
                 this.totalIntervalMs += this.intervalMs ;
                //console.log("IntervalHandle totalIntervalMs:" + this.totalIntervalMs);
                this.Oninterval(this.totalIntervalMs);
                //console.log("IntervalHandle timer:" + this.timer);
            }

        }
        var inportProcesser = new Progresser(500, importing2);
        
        function importing2(totalIntervalMs) {
            var second = (totalIntervalMs / 1000.0).toFixed(1);
            console.log("seconds:" + second + "s..");
        }

</script>
</body>
</html>

我把全部代码贴上来

by.Genesis | 园豆:2824 (老鸟四级) | 2016-10-28 16:37

@by.Genesis: 

没有问题,我的错误,我有个地方改错了,谢了大神!!

摆脱菜鸟 | 园豆:16 (初学一级) | 2016-10-28 16:38
其他回答(1)
0

楼上的解答是正确的,但这是ES6的写法,其实你的问题是一个“js闭包”的问题而已。

解决办法可以先声明一个全局变量

步骤一

var this_ = null;

步骤二

Start: function () {
  //console.log("Start totalIntervalMs:" + this.totalIntervalMs);
  this_ = this;
  this.timer = setInterval( this.IntervalHandle , this.intervalMs);

  /****************************

  说明,问题是你原来是this.IntervalHandle()调用的,但实际上应该是this.IntervalHandle,不需要();

  问题又来了,this.IntervalHandle在setInterval里面单独调用的话那么this.IntervalHandle函数的

  this指向的就是windos对象了。因为setInterval是全局函数。

  ***********************************************/
  //console.log("Start timer:" + this.timer);
},

步骤三

IntervalHandle: function () {
this_.totalIntervalMs += this_.intervalMs ;
  //console.log("IntervalHandle totalIntervalMs:" + this.totalIntervalMs);
  this_.Oninterval(this_.totalIntervalMs);
  //console.log("IntervalHandle timer:" + this.timer);
}

收获园豆:3
张云山 | 园豆:642 (小虾三级) | 2016-10-28 15:02

谢谢,没太看明白,对于闭包一直没理解,js简单的能写,深入的话,尤其是封装的,看着一头雾水啊!

有时间我还是要好好看看那本js高级程序设计,多研究一下开源代码!

支持(0) 反对(0) 摆脱菜鸟 | 园豆:16 (初学一级) | 2016-10-28 15:33
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册