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。



  • 相关阅读:
    eclipse下c/cpp " undefined reference to " or "launch failed binary not found"问题
    blockdev 设置文件预读大小
    宝宝语录
    CentOS修改主机名(hostname)
    subprocess报No such file or directory
    用ldap方式访问AD域的的错误解释
    英特尔的VTd技术是什么?
    This virtual machine requires the VMware keyboard support driver which is not installed
    Linux内核的文件预读详细详解
    UNP总结 Chapter 26~29 线程、IP选项、原始套接字、数据链路访问
  • 原文地址:https://www.cnblogs.com/12606huchao/p/4984299.html
Copyright © 2011-2022 走看看