前言:1.使用setInterval()的定时器会把事件运行的时间也包含在内,如果要精确算定时两个任务之间的时间,可以使用setTimeout()替换。2.当异步事件发生时,如mouse click, a timer firing, or an XMLHttpRequest completing(鼠标点击事件发生、定时器触发事件发生、XMLHttpRequest完成回调触发等),将他们放入执行队列,等待当前代码执行完成。

1. setInterval()基础

setInterval函数的用法与setTimeout完全一致,区别仅仅在于setInterval指定某个任务每隔一段时间就执行一次,也就是无限次的定时执行。

<input type="button" onclick="clearInterval(timer)" value="stop">

<script>
var i = 1
var timer = setInterval(function() {
console.log(2);
}, 1000);
</script>

上面代码表示每隔1000毫秒就输出一个2,直到用户点击了停止按钮。

与setTimeout一样,除了前两个参数,setInterval 方法还可以接受更多的参数,它们会传入回调函数,下面是一个例子。

function f(){
for (var i=0;i<arguments.length;i++){
console.log(arguments[i]);
}
} setInterval(f, 1000, "Hello World");
// Hello World
// Hello World
// Hello World
// ...

如果网页不在浏览器的当前窗口(或tab),许多浏览器限制setInteral指定的反复运行的任务最多每秒执行一次。

setInterval指定的是“开始执行”之间的间隔,并不考虑每次任务执行本身所消耗的事件。因此实际上,两次执行之间的间隔会小于指定的时间。比如,setInterval指定每100ms执行一次,每次执行需要5ms,那么第一次执行结束后95毫秒,第二次执行就会开始。如果某次执行耗时特别长,比如需要105毫秒,那么它结束后,下一次执行就会立即开始。

var i = 1;
var timer = setInterval(function() {
alert(i++);
}, 2000);

上面代码每隔2000毫秒,就跳出一个alert对话框。如果用户一直不点击“确定”,整个浏览器就处于“堵塞”状态,后面的执行就一直无法触发,将会累积起来。举例来说,第一次跳出alert对话框后,用户过了6000毫秒才点击“确定”,那么第二次、第三次、第四次执行将累积起来,它们之间不会再有等待间隔。

为了确保两次执行之间有固定的间隔,可以不用setInterval,而是每次执行结束后,使用setTimeout指定下一次执行的具体时间。上面代码用setTimeout,可以改写如下。

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

上面代码可以确保两次执行的间隔是2000毫秒。

根据这种思路,可以自己部署一个函数,实现间隔时间确定的setInterval的效果。

function interval(func, wait){
var interv = function(){
func.call(null);
setTimeout(interv, wait);
}; setTimeout(interv, wait);
} interval(function(){
console.log(2);
},1000);

上面代码部署了一个interval函数,用循环调用setTimeout模拟了setInterval。

html 5标准规定,setInterval的最短间隔时间是10毫秒,也就是说,小于10毫秒的时间间隔会被调整到10毫秒。

2. setInterval运行机制

setInterval的运行机制是,将指定的代码移出本次执行,等到下一轮Event Loop时,再检查是否到了指定时间。如果到了,就执行对应的代码;如果不到,就等到再下一轮Event Loop时重新判断。这意味着,setTimeout指定的代码,必须等到本次执行的所有代码都执行完,才会执行。

每一轮Event Loop时,都会将“任务队列”中需要执行的任务,一次执行完。setTimeout和setInterval都是把任务添加到“任务队列”的尾部。因此,它们实际上要等到当前脚本的所有同步任务执行完,然后再等到本次Event Loop的“任务队列”的所有任务执行完,才会开始执行。由于前面的任务到底需要多少时间执行完,是不确定的,所以没有办法保证,setTimeout和setInterval指定的任务,一定会按照预定时间执行。

这一点对于setInterval影响尤其大。

setInterval(function(){
console.log(2);
},1000); (function (){
sleeping(3000);
})();

上面的第一行语句要求每隔1000毫秒,就输出一个2。但是,第二行语句需要3000毫秒才能完成,请问会发生什么结果?

结果就是等到第二行语句运行完成以后,立刻连续输出三个2,然后开始每隔1000毫秒,输出一个2。也就是说,setIntervel具有累积效应,如果某个操作特别耗时,超过了setInterval的时间间隔,排在后面的操作会被累积起来,然后在很短的时间内连续触发,这可能或造成性能问题(比如集中发出ajax请求)。

为了进一步理解javascript的单线程模型,请看下面这段伪代码。

function init(){
{ 耗时5ms的某个操作 }
触发mouseClickEvent事件
{ 耗时5ms的某个操作 }
setInterval(timerTask,10);
{ 耗时5ms的某个操作 }
} function handleMouseClick(){
耗时8ms的某个操作
} function timerTask(){
耗时2ms的某个操作
}
init();

请问调用init函数后,这段代码的运行顺序是怎样的?

0-15ms:运行init函数。
15-23ms:运行handleMouseClick函数。请注意,这个函数是在5ms时触发的,应该在那个时候就立即运行,但是由于单线程的关系,必须等到init函数完成之后再运行。
23-25ms:运行timerTask函数。这个函数是在10ms时触发的,规定每10ms运行一次,即在20ms、30ms、40ms等时候运行。由于20ms时,JavaScript线程还有任务在运行,因此必须延迟到前面任务完成时再运行。
30-32ms:运行timerTask函数。
40-42ms:运行timerTask函数。

对于setInterval得使用,个人建议是能不用尽量不用。涉及到必须要的定时器,前文已经叙述可以使用两个setTimeout嵌套组合来实现,并且还能规避掉一些问题得发生。涉及到要用它来制作动画( jQuery就使用setInterval来写动画,也是导致其慢原因之一),更建议使用requestAnimationFrame(RAF),或者直接采用CSS来写(如果可以的话)。

requestAnimationFrame比起setTimeout、setInterval的优势主要有两点:

    1. requestAnimationFrame会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,一般来说,这个频率为每秒60帧。
    2. 在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的的cpu,gpu和内存使用量

文章内容收集与网络 参考:http://www.jeffjade.com/2016/01/10/2016-01-10-javaScript-setInterval/

关于setInterval()你所不知道的地方的更多相关文章

  1. 关于setTimeout()你所不知道的地方,详解setTimeout()

    关于setTimeout()你所不知道的地方,详解setTimeout() 前言:看了这篇文章,1.注意setTimeout引用的是全部变量还是局部变量了,当直接调用外部函数方法时,实际上函数内部的变 ...

  2. 关于setTimeout()你所不知道的地方

    前言:看了这篇文章,1.注意setTimeout引用的是全部变量还是局部变量了,当直接调用外部函数方法时,实际上函数内部的变量已经变成全 局.2.提醒我防止出错的,用匿名函数不容易出错.3.setTi ...

  3. 你所不知道的setInterval

    在你所不知道的setTimeout记载了下setTimeout相关,此篇则整理了下setInterval:作为拥有广泛应用场景(定时器,轮播图,动画效果,自动滚动等等),而又充满各种不确定性的这set ...

  4. 你所不知道的 CSS 阴影技巧与细节 滚动视差?CSS 不在话下 神奇的选择器 :focus-within 当角色转换为面试官之后 NPOI 教程 - 3.2 打印相关设置 前端XSS相关整理 委托入门案例

    你所不知道的 CSS 阴影技巧与细节   关于 CSS 阴影,之前已经有写过一篇,box-shadow 与 filter:drop-shadow 详解及奇技淫巧,介绍了一些关于 box-shadow  ...

  5. 你所不知道的setTimeout

    JavaScript提供定时执行代码的功能,叫做定时器(timer),主要由setTimeout()和setInterval()这两个函数来完成.它们向任务队列添加定时任务.初始接触它的人都觉得好简单 ...

  6. 你所不知道的SQL Server数据库启动过程,以及启动不起来的各种问题的分析及解决技巧

    目前SQL Server数据库作为微软一款优秀的RDBMS,其本身启动的时候是很少出问题的,我们在平时用的时候,很少关注起启动过程,或者很少了解其底层运行过程,大部分的过程只关注其内部的表.存储过程. ...

  7. 你所不知道的html5与html中的那些事第三篇

    文章简介: 关于html5相信大家早已经耳熟能详,但是他真正的意义在具体的开发中会有什么作用呢?相对于html,他又有怎样的新的定义与新理念在里面呢?为什么一些专家认为html5完全完成后,所有的工作 ...

  8. 你所不知道的五件事情--java.util.concurrent(第二部分)

    这是Ted Neward在IBM developerWorks中5 things系列文章中的一篇,仍然讲述了关于Java并发集合API的一些应用窍门,值得大家学习.(2010.06.17最后更新) 摘 ...

  9. 你所不知道的Html5那些事(一)

    文章简介:       关于html5相信大家早已经耳熟能详,但是他真正的意义在具体的开发中会有什么作用呢?相对于html,他又有怎样的新的定义与新理念在里面呢?为什么一些专家认为html5完全完成后 ...

随机推荐

  1. HDOJ 1008. Elevator 简单模拟水题

    Elevator Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Su ...

  2. JUnit 4 与 TestNG 对比

    原文出处: 付学良的网志 原文出处2: http://www.importnew.com/16270.html -------------------------------------------- ...

  3. map 函数----filter函数

    # map 函数 l = (1,2,4,5,6,7,8,9,) print(list(map(lambda x:x**2,l)))#使用list类型((map函数(lambda 匿名函数定义x值:x* ...

  4. 将字符串中的URL 解析,获取内容

    parse_str() : parse_str("name=Bill&age=60"); echo $name."<br>";//Bill ...

  5. jsp编码过程

    pageEncoding是jsp文件本身的编码 contentType的charset是指浏览器到服务器发送时使用的编码:以及服务器返回到浏览器使用的编码 JSP要经过三次的“编码” 第一阶段会用JS ...

  6. install scrapy-redis on centos

    wget http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpmrpm -ivh epel-release- ...

  7. destoon : 后台无法登录问题解决

    经常有朋友在destoon搬家的时候 , 数据还原之后 , 会出现后台无法登录的情况 . 具体表现为后台帐号密码输入后点击确定 , 页面刷新 .并没有跳转到相应后台页面 . 但是如果帐号密码输入错误 ...

  8. mongodb未授权访问漏洞

    catalogue . mongodb安装 . 未授权访问漏洞 . 漏洞修复及加固 . 自动化检测点 1. mongodb安装 apt-get install mongodb 0x1: 创建数据库目录 ...

  9. canvas-渐变文字

    html要求: <body onload="draw('canvas');"> body这里的onload一定要写,在这个处理模式下,是在body这里执行加载页面完成后 ...

  10. Mysql 常用 SQL 语句集锦

    Mysql 常用 SQL 语句集锦 基础篇 //查询时间,友好提示 $sql = "select date_format(create_time, '%Y-%m-%d') as day fr ...