美文网首页
定时器使用不当造成的问题

定时器使用不当造成的问题

作者: 张培_ | 来源:发表于2017-12-12 22:27 被阅读125次

    情景描述

    • 需要在某个操作执行成功之后
    • 开始倒计时五秒弹回首页
    • 因此设置了一个每隔1s执行一次setState将显示在屏幕上数字减一
    componentWillReceiveProps(nextProps) {
        if (nextProps.isChangePasswordSucceed) {
          this.timerID = setInterval(::this.tick, 1000)
        }
      }
      
    tick() {
        if (this.state.timer > 0) {
          this.setState({
            timer: this.state.timer - 1
          })
        } else {
          clearInterval(this.timerID)
          this.props.actions.jumpHome()
        }
      }
    
    • 但却发现显示在屏幕上的数字直接从5到了0,然后发现tick的else仍然一直在执行

    知识补充

    • Q1:setTimeout和setInterval的返回值是什么?有什么作用
    • A1:他们的返回值都是当前定时器的ID,在用一个window或者frame中每当创建一个新的定时器(不论是setInterval还是setTimeout)都会在内存中创建一个定时器,他们的ID都是按照创建顺序依次加一的,并且setTimeout和setInterval的定时器ID都是在同一个ID池中,因此如果先创建了一个setTimeout的ID是1,那么下一个创建的setInterval的ID是2
    • Q2:那么这些定时器的ID有什么作用呢??
    • A2:作用大了!!!
      • 1.作为clearInterval或者clearTimeout的参数将定时器在内存中完全清除
      • 2.当定时器出现执行间隔变短,或者其他异常情况可以通过打印定时器ID的方式检测是否创建了多个定时器

    问题分析

    • Q1:很显然,定时器的执行间隔远远小于1s,这是为什么呢?

    • A1:那么这里剖析一下为什么setInterval的执行

      • 首先创建一个定时器(每隔1s执行一次)
      • 过了1s之后,会将操作放入异步执行队列
      • 如果此时主线程没有工作
      • 那么会立刻执行这个操作(以上是正常的执行情况)

      • 定时器做得事情是:
        • 每隔1s查看异步执行队列中有没有同一个定时器的function
          • 没有:将fucntion写入异步执行队列
          • 有:就不将function写入(简而言之:这一次本应该执行的fucntion被直接跳过了),直接忽略
      • 主线程做得事情是:
        • 手头工作一旦完成立刻查看异步执行队列
        • 按照一致队列的顺序依次执行队列中的任务
      • 现在来分析一下为什么定时器会加速
        • s1:当主线程一直有东西在执行,
          • 导致第一次定时器的执行就晚了一些
          • 然后定时器的functin执行时间又小于1s
          • 并且在此期间已经在异步队列中插入了下一次的fucntion
          • 会导致第一次的执行和第二次的执行间隔小于1s
        • s2:创建了多个定时器
          • 导致相似的时刻有多个同样但是来自不同定时器的function被加入异步队列
          • 恰巧每个function的执行时间很短,会导致1s内执行了多个function
      • 因此总结来说,发现定时器加速执行,可以先判断第二种情况是否发生了
        • 判断方式:通过打印定时器的ID看看当前tab中出现的到底是一个ID还是多个ID
    • Q2:为什么tick的else会执行说明一定执行clearInterval,那么为什么定时器还在呢?

    • A2:这就更加说明了你创建了多个定时器,创建定时器的时候通常会将定时器的ID赋给一个值(比如本文中的this.timerID)然后使用它作为clearInterval的参数。然而

      • 当你创建了多个定时器
      • 这时候this.timerID一定指向的是最后一个定时器
      • 就说明之前创建的定时器就在内存在但是已经没有引用了
      • 所以之前创建的那些定时器,除非你刷新页面更新window对象,否则永远没有办法把他停止了
    • 所以!!注意检查定时器的ID很重要

    • Q3:那么是什么造成创建了那么多次的定时器呢?

    • A3:这就是使用componentWillReceiveProps中必须要注意的地方:

      • componentWillReceiveProps函数只要props数据变化就会被调用
      • 因此我们通常使用if包住想在其中执行的代码
      • 但是如果if每次都被判为true就会导致代码块被反复执行
      • 所以在componentWillReceiveProps中执行函数,一定要有万全的判断并且考虑如果这么判断代码块会被执行几次
      • 总结:想在componentWillReceiveProps中创建定时器或者弹出模态框等操作一定要考虑如何进行if判断能保证这个操作只会被执行一次

        • 必须要让if的判断更加全面
    • 当前解决,就是当this.timerID不再是undefined那么就不能再进入if true了

    相关文章

      网友评论

          本文标题:定时器使用不当造成的问题

          本文链接:https://www.haomeiwen.com/subject/ukjoixtx.html