Js中setTimeout()和setInterval() 何时被调用执行的用法


Posted in Javascript onApril 12, 2013

定义
setTimeout()和setInterval()经常被用来处理延时和定时任务。setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式,而setInterval()则可以在每隔指定的毫秒数循环调用函数或表达式,直到clearInterval把它清除。
从定义上我们可以看到两个函数十分类似,只不过前者执行一次,而后者可以执行多次,两个函数的参数也相同,第一个参数是要执行的code或句柄,第二个是延迟的毫秒数。
很简单的定义,使用起来也很简单,但有时候我们的代码并不是按照我们的想象精确时间被调用的,很让人困惑

简单示例
看个简单的例子,简单页面在加载完两秒后,写下Delayed alert!

setTimeout('document.write("Delayed alert!");', 2000);

看起来很合理,我们再看个setInterVal()方法的例子
var num = 0;
        var i = setInterval(function() {
            num++;
            var date = new Date();
            document.write(date.getMinutes() + ':' + date.getSeconds() + ':' + date.getMilliseconds() + '<br>');
            if (num > 10)
                clearInterval(i);
        }, 1000);

页面每隔1秒记录一次当前时间(分钟:秒:毫秒),记录十次后清除,不再记录。考虑到代码执行时间可能记录的不是执行时间,但时间间隔应该是一样的,看看结果
:38:116
:39:130
:40:144
:41:158
:42:172
:43:186
:44:200
:45:214
:46:228
:47:242
:48:256

为什么
时间间隔几乎是1000毫秒,但不精确,这是为什么呢?原因在于我们对JavaScript定时器存在一个误解,JavaScript其实是运行在单线程的环境中的,这就意味着定时器仅仅是计划代码在未来的某个时间执行,而具体执行时机是不能保证的,因为页面的生命周期中,不同时间可能有其他代码在控制JavaScript进程。在页面下载完成后代码的运行、事件处理程序、Ajax回调函数都是使用同样的线程,实际上浏览器负责进行排序,指派某段程序在某个时间点运行的优先级。
我们把效果放大一下看看,添加一个耗时的任务
function test() {
            for (var i = 0; i < 500000; i++) {
                var div = document.createElement('div');
                div.setAttribute('id', 'testDiv');
                document.body.appendChild(div);
                document.body.removeChild(div);
            }
        }
        setInterval(test, 10);
        var num = 0;
        var i = setInterval(function() {
            num++;
            var date = new Date();
            document.write(date.getMinutes() + ':' + date.getSeconds() + ':' + date.getMilliseconds() + '<br>');
            if (num > 10)
                clearInterval(i);
        }, 1000);

我们又加入了一个定时任务,看看结果
:9:222
:12:482
:16:8
:19:143
:22:631
:25:888
:28:712
:32:381
:34:146
:35:565
:37:406

这下效果明显了,差距甚至都超过了3秒,而且差距很不一致。
我们可以可以把JavaScript想象成在时间线上运行。当页面载入的时候首先执行的是页面生命周期后面要用的方法和变量声明和数据处理,在这之后JavaScript进程将等待更多代码执行。当进程空闲的时候,下一段代码会被触发

除了主JavaScript进程外,还需要一个在进程下一次空闲时执行的代码队列。随着页面生命周期推移,代码会按照执行顺序添加入队列,例如当按钮被按下的时候他的事件处理程序会被添加到队列中,并在下一个可能时间内执行。在接到某个Ajax响应时,回调函数的代码会被添加到队列。JavaScript中没有任何代码是立即执行的,但一旦进程空闲则尽快执行。定时器对队列的工作方式是当特定时间过去后将代码插入,这并不意味着它会马上执行,只能表示它尽快执行。
知道了这些后,我们就能明白,如果想要精确的时间控制,是不能依赖于JavaScript的setTimeout函数的。

重复的定时器
使用 setInterval() 创建的定时器可以使代码循环执行,到有指定效果的时候,清除interval就可以,如下例

var my_interval = setInterval(function () {
            if (condition) {
                //..........
            } else {
                clearInterval(my_interval);
            }
        }, 100);

但这个方式的问题在于定时器的代码可能在代码再次被添加到队列之前还没有执行完成,结果导致循环内的判断条件不准确,代码多执行几次,之间没有停顿。不过JavaScript已经解决这个问题,当使用setInterval()时,仅当没有该定时器的其他代码实例时才将定时器代码插入队列。这样确保了定时器代码加入到队列的最小时间间隔为指定间隔。

这样的规则带来两个问题

1.1. 某些间隔会被跳过
2.2.多个定时器的代码执行之间的间隔可能比预期要小
为了避免这两个缺点,我们可以使用setTimeout()来实现重复的定时器

setTimeout(function () {
            //code
            setTimeout(arguments.callee, interval);
        }, interval)

这样每次函数执行的时候都会创建一个新的定时器,第二个setTimeout()调用使用了agrument.callee 来获取当前实行函数的引用,并设置另外一个新定时器。这样做可以保证在代码执行完成前不会有新的定时器插入,并且下一次定时器代码执行之前至少要间隔指定时间,避免连续运行。
setTimeout(function () {
            var div = document.getElementById('moveDiv');
            var left = parseInt(div.style.left) + 5;
            div.style.left = left + 'px';
            if (left < 200) {
                setTimeout(arguments.callee, 50);
            }
        }, 50);

这段定时器代码每次执行的时候,把一个div向右移动5px,当坐标大于200的时候停止。
Javascript 相关文章推荐
javascript 遍历验证所有文本框的值
Aug 27 Javascript
JS实现清除指定cookies的方法
Sep 20 Javascript
javascript实现动态模态绑定grid过程代码
Sep 22 Javascript
transport.js和jquery冲突问题的解决方法
Feb 10 Javascript
bootstrapfileinput实现文件自动上传
Nov 08 Javascript
解决在vue项目中,发版之后,背景图片报错,路径不对的问题
Mar 06 Javascript
在vue-cli搭建的项目中增加后台mock接口的方法
Apr 26 Javascript
React通过redux-persist持久化数据存储的方法示例
Feb 14 Javascript
webpack 如何解析代码模块路径的实现
Sep 04 Javascript
解决$store.getters调用不执行的问题
Nov 08 Javascript
js 将多个对象合并成一个对象 assign方法的实现
Sep 24 Javascript
Ant-design-vue Table组件customRow属性的使用说明
Oct 28 Javascript
js实现单一html页面两套css切换代码
Apr 11 #Javascript
获取内联和链接中的样式(js代码)
Apr 11 #Javascript
JavaScript在XHTML中的用法详解
Apr 11 #Javascript
JavaScript中的noscript元素属性位置及作用介绍
Apr 11 #Javascript
javascript标签在页面中的位置探讨
Apr 11 #Javascript
JS添加删除一组文本框并对输入信息加以验证判断其正确性
Apr 11 #Javascript
如何使用json在前后台进行数据传输实例介绍
Apr 11 #Javascript
You might like
15个小时----从修改程序到自己些程序
2006/10/09 PHP
邮箱正则表达式实现代码(针对php)
2013/06/21 PHP
php根据isbn书号查询amazon网站上的图书信息的示例
2014/02/13 PHP
ThinkPHP模版引擎之变量输出详解
2014/12/05 PHP
PHP中模拟链表和链表的基本操作示例
2016/02/27 PHP
phpmyadmin在宝塔面板里进不去的解决方案
2020/07/06 PHP
jquery ui dialog里调用datepicker的问题
2009/08/06 Javascript
9个JavaScript评级/投票插件
2010/01/18 Javascript
常见表单重复提交问题整理及解决方法
2013/11/13 Javascript
jQuery经过一段时间自动隐藏指定元素的方法
2015/03/17 Javascript
JavaScript每天定时更换皮肤样式的方法
2015/07/01 Javascript
javascript显示上周、上个月日期的处理方法
2016/02/03 Javascript
JS简单实现禁止访问某个页面的方法
2016/09/13 Javascript
jQuery图片轮播实现并封装(一)
2016/12/03 Javascript
jquery.form.js异步提交表单详解
2017/04/25 jQuery
理解python多线程(python多线程简明教程)
2014/06/09 Python
图文讲解选择排序算法的原理及在Python中的实现
2016/05/04 Python
Python编程pygame模块实现移动的小车示例代码
2018/01/03 Python
Python基于列表list实现的CRUD操作功能示例
2018/01/05 Python
Scrapy-Redis结合POST请求获取数据的方法示例
2019/05/07 Python
pyQt5实时刷新界面的示例
2019/06/25 Python
对Python函数设计规范详解
2019/07/19 Python
Python操作SQLite数据库过程解析
2019/09/02 Python
Python完全识别验证码自动登录实例详解
2019/11/24 Python
Python‘==‘ 及 ‘is‘相关原理解析
2020/09/05 Python
Pycharm操作Git及GitHub的步骤详解
2020/10/27 Python
大学生简历中个人的自我评价
2013/10/06 职场文书
房地产开发计划书
2014/01/10 职场文书
门诊手术室工作制度
2014/01/30 职场文书
消防安全管理制度
2014/02/01 职场文书
派出所副所长四风问题个人整改措施思想汇报
2014/10/13 职场文书
管理人员岗位职责
2015/02/14 职场文书
市场督导岗位职责
2015/04/10 职场文书
小学生作文之《压岁钱的烦恼》
2019/09/27 职场文书
漫改真人电影「萌系男友是燃燃的橘色」公开先导视觉图
2022/03/21 日漫
win sever 2022如何占用操作主机角色
2022/06/25 Servers