使用 setTimeout()和 setInterval()创建的定时器可以用于实现有趣且有用的功能。执行时机是不能保证的,因为在页面的生命周期中,不同时间可能有其他代码在控制 JavaScript 进程。在页面下载完后的代码运行、事件处理程序、Ajax 回调函数都必须使用同样的线程来执行。实际上,浏览器负责进行排序,指派某段代码在某个时间点运行的优先级。有关于js的单线程请点击:浏览器的多进程

可以把 JavaScript 想象成在时间线上运行的。当页面载入时,首先执行是任何包含在<script>元素中的代码,通常是页面生命周期后面要用到的一些简单的函数和变量的声明,不过有时候也包含一些初始数据的处理。在这之后,JJavaScript 主线程将等待更多代码执行。例如,当点击某个按钮时,onclick 事件处理程序会立刻执行,只要 JavaScript 主线程处于空闲状态。这样一个页面的时间线类似如图

除了JavaScript 主线程外,还有一个需要在进程下一次空闲时执行的代码队列。随着页面在其生命周期中的推移,代码会按照执行顺序添加入队列。例如,当某个按钮被按下时,它的事件处理程序代码就会被添加到队列中,并在下一个可能的时间里执行。当接收到某个 Ajax 响应时,回调函数的代码会被添加到队列。在 JavaScript 中没有任何代码是立刻执行的,但一旦主线程空闲则尽快执行。

定时器对队列的工作方式是,当特定时间过去后将代码插入。注意,给队列添加代码并不意味着对它立刻执行,而只能表示它会尽快执行。设定一个 150ms 后执行的定时器不代表到了 150ms 代码就立刻执行,它表示代码会在 150ms 后被加入到队列中。如果在这个时间点上,队列中没有其他东西,那么这段代码就会被执行,表面上看上去好像代码就在精确指定的时间点上执行了。其他情况下,代码可能明显地等待更长时间才执行。

请看以下代码:

var btn = document.getElementById("my-btn");

btn.onclick = function(){

setTimeout(function(){

document.getElementById("message").style.visibility = "visible";

}, 250);

//其他代码

};

在这里给一个按钮设置了一个事件处理程序。事件处理程序设置了一个 250ms 后调用的定时器。点击该按钮后,首先将 onclick 事件处理程序加入队列。该程序执行后才设置定时器,再有 250ms 后,指定的代码才被添加到队列中等待执行。实际上,对 setTimeout()的调用表示要晚点执行某些代码。

关于定时器要记住的最重要的事情是,指定的时间间隔表示何时将定时器的代码添加到队列,而不是何时实际执行代码。如果前面例子中的 onclick 事件处理程序执行了 300ms,那么定时器的代码至少要在定时器设置之后的 300ms 后才会被执行。队列中所有的代码都要等到 JavaScript 进程空闲之后才能执行,而不管它们是如何添加到队列中的。如图

重复的定时器

使用 setInterval()创建的定时器确保了定时器代码规则地插入队列中。这个方式的问题在于,定时器代码可能在代码再次被添加到队列之前还没有完成执行,结果导致定时器代码连续运行好几次,而之间没有任何停顿。幸好,JavaScript 引擎够聪明,能避免这个问题。当使用 setInterval()时,仅当没有该定时器的任何其他代码实例时,才将定时器代码添加到队列中。这确保了定时器代码加入到队列中的最小时间间隔为指定间隔。

这种重复定时器的规则有两个问题:(1) 某些间隔会被跳过;(2) 多个定时器的代码执行之间的间隔可能会比预期的小。假设,某个 onclick 事件处理程序使用 setInterval()设置了一个 200ms 间隔的重复定时器。如果事件处理程序花了 300ms 多一点的时间完成,同时定时器代码也花了差不多的时间,就会同时出现跳过间隔且连续运行定时器代码的情况。

这个例子中的第 1 个定时器是在 205ms 处添加到队列中的,但是直到过了 300ms 处才能够执行。当执行这个定时器代码时,在 405ms 处又给队列添加了另外一个副本。在下一个间隔,即 605ms 处,第一个定时器代码仍在运行,同时在队列中已经有了一个定时器代码的实例。结果是,在这个时间点上的定时器代码不会被添加到队列中。结果在 5ms 处添加的定时器代码结束之后,405ms 处添加的定时器代码就立刻执行。

为了避免 setInterval()的重复定时器的这 2 个缺点,你可以用如下模式使用链式 setTimeout() 调用。

setTimeout(function(){

//处理中

setTimeout(arguments.callee, interval);

}, interval);

这个模式链式调用了 setTimeout(),每次函数执行的时候都会创建一个新的定时器。第二个setTimeout()调用使用了 arguments.callee 来获取对当前执行的函数的引用,并为其设置另外一个定时器。这样做的好处是,在前一个定时器代码执行完之前,不会向队列插入新的定时器代码,确保不会有任何缺失的间隔。而且,它可以保证在下一次定时器代码执行之前,至少要等待指定的间隔,避免了连续的运行。这个模式主要用于重复定时器,如下例所示。

setTimeout(function(){

var div = document.getElementById("myDiv");

left = parseInt(div.style.left) + 5;

div.style.left = left + "px";

if (left < 200){

setTimeout(arguments.callee, 50);

}

}, 50);

这段定时器代码每次执行的时候将一个<div>元素向右移动,当左坐标在 200 像素的时候停止。

JavaScript 动画中使用这个模式很常见。

链式调用setTimeout()与setInterval()的区别相关推荐

  1. 实现同步请求_图解 Promise 实现原理(二)—— Promise 链式调用

    摘要 很多同学在学习 Promise 时,知其然却不知其所以然,对其中的用法理解不了.本系列文章由浅入深逐步实现 Promise,并结合流程图.实例以及动画进行演示,达到深刻理解 Promise 用法 ...

  2. JS setTimeout和setInterval的区别

    1.setTimeout和setInterval都属于JS中的定时器,可以规定延迟时间再执行某个操作,不同的是setTimeout在规定时间后执行完某个操作就停止了,而setInterval则可以一直 ...

  3. 10.setTimeout和setInterval的区别以及模拟实现:

    10.setTimeout和setInterval的区别以及模拟实现: setTimeout:推迟ms后执行一次:(延时器) setInterval:间隔ms就重复执行.(重复定时器) 使用setTi ...

  4. 彻底掌握 Promise-原生Promise的实现(二) Promise的链式调用

    在 彻底掌握 Promise- 原生 Promise 的实现(一) 已经初步实现了 promise 的简易版本,这距离实现完整版本的 Promise 还有一段距离,下面我们将在简易版本的基础上增加 P ...

  5. Android 快速实现新手引导层的库,通过简洁链式调用,一行代码实现引导层的显示

    NewbieGuide 项目地址:huburt-Hu/NewbieGuide  简介:Android 快速实现新手引导层的库,通过简洁链式调用,一行代码实现引导层的显示 更多:作者   提 Bug 标 ...

  6. JS 通过 Promise 实现延时执行,支持链式调用

    JS 通过 Promise 实现延时执行,支持链式调用 延时执行 sleep 版本一 同步执行 异步方式 sleep 版本二 支持链式调用 版本一 版本二 参考资料 延时执行 定义sleep函数 sl ...

  7. javascript --- 对象的方式体验链式调用

    将功能相近的方法写入同一个对象中,是一个很好的编程习惯,便于后期的维护和前期的开发. foo1 var fooObj = {foo1: function() {console.log('foo1'); ...

  8. java中链式调用_Java及Android中常用链式调用写法简单示例

    本文实例讲述了Java及Android中常用链式调用写法.分享给大家供大家参考,具体如下: 最近发现,目前大火的许多开源框架中,大多都使用了一种"(方法).(方法).(方法)"的形 ...

  9. setTimeout和setInterval的区别

    setTimeout和setInterval的区别 javascript都是以单线程的方式运行于浏览器的javascript引擎中的, setTimeout和setInterval的作用只是把你要执行 ...

最新文章

  1. 444牛X的日常口语
  2. linux之file命令总结
  3. jsoncpp学习笔记
  4. Algs4-1.4.18数组的局部最小元素
  5. java怎么碰到异常跳过继续执行_Java异常处理很难吗?BAT大厂的架构师是怎么处理Java异常的?...
  6. 任务管理器只有概要信息解决办法
  7. SharePoint服务器端对象模型 之 访问文件和文件夹(Part 4)
  8. 一些值得好好学习的博客或者网站
  9. 计算机无法映射网络驱动器,win7系统无法映射网络驱动器的解决方法
  10. GMV远超预期背后,快手电商做对了什么?
  11. webgl 地球_使用WebGL和JavaScript构建地球
  12. 洞见趋势系列(二)特征工程
  13. 6s测试信号软件,手机信号强度测试:苹果iPhone 6s不敌三星S6
  14. 华为云牛客网之学生华为云服务器体验之路_1云服务器的购买篇
  15. protobuf java代码生成及实例
  16. java定义hashmap_Java用自定义的类型作为HashMap的key
  17. 摇号系统 - 【python】
  18. 灰色马尔科夫链matlab,基于灰色-马尔科夫模型的电力功率预测
  19. 基于Spring Session实现JIM分布式Session
  20. LSP标识符(LSP ID)

热门文章

  1. 数学--数论--二次探测定理
  2. Apache Tika:通用的内容分析工具
  3. Ubuntu14.04系统下安装配置OpenCV 4.0.0开发环境全过程
  4. linux驱动模块命令大全insmod/rmmod/modprobe/depmod/lsmod
  5. 如何在keil下实现单工程多目标的设置(选择性自动编译)
  6. KMP算法中next数组的理解与算法的实现(java语言)
  7. 编程学习--从入门到放弃
  8. Eigen入门之密集矩阵 7 - Map class:连接Eigen与C++的数据
  9. python集群_使用Python集群文档
  10. 专家建议用南方的养老金拿去救济东北,网友炸锅了