zoukankan      html  css  js  c++  java
  • setInterval和setTimeout

    setTimeout和setInterval的基本用法我们不谈,无非是1.指定延迟后调用函数,2.以指定周期调用函数

    让我们想象一个意外情况,比如说下面的setInterval

    setInterval(function(){
        func(i++);},100)

      

    我们以每100毫秒调用一次func函数,如果func的执行时间少于100毫秒的话好办,在遇到下一个100毫秒前就能够执行完:

    但如果func的执行时间大于100毫秒,该触发下一个func函数时之前的还没有执行完怎么办?(前提是你要知道javascript只有单线程,不存在同时执行致命一说,才会有这个问题)。答案如下图所示,那么第二个func会在队列(这里的队列是指event loop,在下文中会详细提到)中等待,直到第一个函数执行完

    如果第一个函数的执行时间特别长,在执行的过程中本应触发了许多个func怎么办,那么所有这些应该触发的函数都会进入队列吗?

    不,只要发现队列中有一个被执行的函数存在,那么其他的统统忽略。如下图,在第300毫秒和400毫秒处的回调都被抛弃,一旦第一个函数执行完后,接着执行队列中的第二个,即使这个函数已经“过时”很久了。

    还有一点,虽然你在setInterval的里指定的周期是100毫秒,但它并不能保证两个函数之间调用的间隔一定是一百毫秒。在上面的情况中,如果队列中的第二个函数时在第450毫秒处结束的话,在第500毫秒时,它会继续执行下一轮func,也就是说这之间的间隔只有50毫秒,而非周期100毫秒

    那如果我想保证每次执行的间隔应该怎么办?用setTimeout,比如下面的代码:

    var i =1  var timer = setTimeout(function(){
        alert(i++)
        timer = setTimeout(arguments.callee,2000)},2000)

     setInterval的问题:

    1. 某些间隔会被跳过

    2.多个定时器的代码执行之间的间隔可能比预期要小

     所以常用setTimeout代替setInterval

    setInterval(fn,time)
    //↓↓↓↓↓↓↓↓↓↓↓↓
    setTimeout(function(){
        fn();
        setTimeout(arguments.callee,time);
    },time);
    这样每次函数执行的时候都会创建一个新的定时器,第二个setTimeout()调用使用了agrument.callee 来获取当前实行函数的引用,并设置另外一个新定时器。这样做可以保证在代码执行完成前不会有新的定时器插入,并且下一次定时器代码执行之前至少要间隔指定时间,避免连续运行。


    setInterval 的堆调用
    setTimeout 只会执行回调函数一次,不过 setInterval - 正如名字建议的 - 会每隔 X 毫秒执行函数一次。 但是却不鼓励使用这个函数。
    当回调函数的执行被阻塞时,setInterval 仍然会发布更多的回调指令。在很小的定时间隔情况下,这会导致回调函数被堆积起来。
    function foo(){
    // 阻塞执行 1 秒
    }
    setInterval(foo, 100);
    上面代码中,foo 会执行一次随后被阻塞了一秒钟。
    在 foo 被阻塞的时候,setInterval 仍然在组织将来对回调函数的调用。 因此,当第一次 foo 函数调用结束时,已经有 10 次函数调用在等待执行。
    处理可能的阻塞调用
    最简单也是最容易控制的方案,是在回调函数内部使用 setTimeout 函数。
    function foo(){
    // 阻塞执行 1 秒
    setTimeout(foo, 100);
    }
    foo();
    这样不仅封装了 setTimeout 回调函数,而且阻止了调用指令的堆积,可以有更多的控制。 foo 函数现在可以控制是否继续执行还是终止执行。
    手工清空定时器
    可以通过将定时时产生的 ID 标识传递给 clearTimeout 或者 clearInterval函数来清除定时, 至于使用哪个函数取决于调用的时候使用的是 setTimeout还是 setInterval。
    var id = setTimeout(foo, 1000);
    clearTimeout(id);

    隐藏使用 eval
    setTimeout 和 setInterval 也接受第一个参数为字符串的情况。 这个特性绝对不要使用,因为它在内部使用了 eval。
    注意: 由于定时器函数不是 ECMAScript 的标准,如何解析字符串参数在不同的 JavaScript 引擎实现中可能不同。 事实上,微软的 JScript 会使用 Function 构造函数来代替 eval 的使用。
    function foo() {
    // 将会被调用,输出2

    console.log(2);
    }

    function bar() {
    function foo() {
    // 不会被调用,不输出22

    console.log(22);
    }
    setTimeout('foo()', 1000);
    }
    bar();
    由于 eval 在这种情况下不是被直接调用,因此传递到 setTimeout 的字符串会自全局作用域中执行; 因此,上面的回调函数使用的不是定义在 bar 作用域中的局部变量 foo。



  • 相关阅读:
    SQL 视图 局部变量 全局变量 条件语句 事务 触发器
    asp.net中的cookie
    Ajax 学习笔记
    接口与抽象类
    log4net日志组件
    StringBulider简单用法
    Web.Config文件详解
    性能优化之无阻塞加载脚步方法比较
    vue双向数据绑定原理探究(附demo)
    让你的JS更优雅的小技巧
  • 原文地址:https://www.cnblogs.com/12606huchao/p/4984299.html
Copyright © 2011-2022 走看看