这里有新鲜出炉的 Javascript 教程,程序狗速度看过来!
Javascript 是一种由 Netscape 的 LiveScript 发展而来的原型化继承的基于对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如 Perl,遗留的速度问题,为客户提供更流畅的浏览效果。
这篇文章主要帮助大家学习理解 javascript 定时器中的 setTimeout 与 setInterval,从实例出发进行深入探讨,感兴趣的小伙伴们可以参考一下
一、解释说明
1、概述
setTimeout:在指定的延迟时间之后调用一个函数或者执行一个代码片段
setInterval:周期性地调用一个函数 (function) 或者执行一段代码。
2、语法
setTimeout:
- var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]);
- var timeoutID = window.setTimeout(code, delay);
setInterval
- var intervalID = window.setInterval(func, delay[, param1, param2, ...]);
- var intervalID = window.setInterval(code, delay);
- <script type="text/javascript">
- setTimeout(function(param) {
- alert(param)
- },
- 100, 'ok');
- </script>
简单测试了下第五条,在我的电脑上面分别使用 firefox 与 IE9 测试,前者可以顺利弹出 ok,后者弹出了 undefined。
二、"this" 问题
由 setTimeout() 调用的代码运行在与所在函数完全分离的执行环境上. 这会导致, 这些代码中包含的 this 关键字会指向 window (全局对象) 对象, 这和所期望的 this 的值是不一样的。setInterval 的情况类似。
- <script type="text/javascript">
- //this指向window
- function shape(name) {
- this.name = name;
- this.timer = function() {
- alert('my shape is ' + this.name)
- };
- setTimeout(this.timer, 50);
- }
- new shape('rectangle');
- </script>
没有被传进去,分别用 chrome,firefox 和 IE9 实验了下,都是这个结果。
解决方法一:
- <script type="text/javascript">
- function shape(name) {
- this.name = name;
- this.timer = function() {
- alert('my shape is ' + this.name)
- };
- var _this = this;
- setTimeout(function() {
- _this.timer.call(_this)
- },
- 50);
- }
- new shape('rectangle');
- </script>
设置一个局部变量_this,然后放到 setTimeout 的函数变量中,timer 执行 call 或 apply,设置 this 值。
function 能够调用局部变量_this,多亏了 Javascript 的闭包。里面涉及了作用域链等知识,有兴趣的可以自己去了解下,这里不展开了。
解决方法二:
这个方法有点高大上。自定义了 setTimeout 与 setInterval。而且还扩展了低版本的 IE 浏览器,不支持向延迟函数传递额外参数的问题。
- <script type="text/javascript">
- //自定义setTimeout与setInterval
- var __nativeST__ = window.setTimeout,
- __nativeSI__ = window.setInterval;
- window.setTimeout = function(vCallback, nDelay
- /*, argumentToPass1, argumentToPass2, etc. */
- ) {
- var oThis = this,
- aArgs = Array.prototype.slice.call(arguments, 2);
- return __nativeST__(vCallback instanceof Function ?
- function() {
- vCallback.apply(oThis, aArgs);
- }: vCallback, nDelay);
- };
- window.setInterval = function(vCallback, nDelay
- /*, argumentToPass1, argumentToPass2, etc. */
- ) {
- var oThis = this,
- aArgs = Array.prototype.slice.call(arguments, 2);
- return __nativeSI__(vCallback instanceof Function ?
- function() {
- vCallback.apply(oThis, aArgs);
- }: vCallback, nDelay);
- };
- function shape(name) {
- this.name = name;
- this.timer = function(other) {
- alert('my shape is ' + this.name);
- alert('extra param is ' + other);
- };
- }
- var rectangle = new shape('rectangle');
- setTimeout.call(rectangle, rectangle.timer, 50, 'other');
- </script>
1、设置局部变量,赋值为原生的 setTimeout 与 setInterval
2、扩展 setTimeout 与 setInterval,aArgs 通过分割 arguments 这个变量,获取到额外的参数数组
3、用 vCallback instanceof Function 判断这是不是一个函数或代码,如果是函数就用 apply 执行
4、setTimeout 用 call 执行,设定 this 对象,以及其它的 func、delay 等参数
5、顺便扩展 setTimeout,IE 低版本的浏览器也能执行额外参数
三、setTimeout 与 setInterval 之间的一个区别
- <script type="text/javascript">
- setTimeout(function() {
- /* Some long block of code... */
- setTimeout(arguments.callee, 100);
- },
- 10);
- setInterval(function() {
- /* Some long block of code... */
- },
- 100);
- </script>
看上去,两个功能是差不多的,但是里面其实是不一样的。
setTimeout 回调函数的执行和上一次执行之间的间隔至少有 100ms(可能会更多,但不会少于 100ms)
setInterval 的回调函数将尝试每隔 100ms 执行一次,不论上次是否执行完毕,时间间隔理论上是会 <=delay 的。
setInterval:
- <script type="text/javascript">
- function sleep(ms) {
- var start = new Date();
- while (new Date() - start <= ms) {}
- }
- var endTime = null;
- var i = 0;
- setInterval(count, 100);
- function count() {
- var elapsedTime = endTime ? (new Date() - endTime) : 100;
- i++;
- console.log('current count: ' + i + '.' + 'elapsed time: ' + elapsedTime + 'ms');
- sleep(200);
- endTime = new Date();
- }
- </script>
从 firefox 的 firebug 可以查看到,时间间隔很不规则。
情况大致是这样的:由于 count 函数的执行时间远大于 setInterval 的定时间隔,那么定时触发线程就会源源不断的产生异步定时事件,并放到任务队列尾而不管它们是否已被处理,但一旦一个定时事件任务处理完,这些排列中的剩余定时事件就依次不间断的被执行。
setTimeout:
- <script type="text/javascript">
- function sleep(ms) {
- var start = new Date();
- while (new Date() - start <= ms) {}
- }
- var endTime = null;
- var i = 0;
- setTimeout(count, 100);
- function count() {
- var elapsedTime = endTime ? (new Date() - endTime) : 100;
- i++;
- console.log('current count: ' + i + '.' + 'elapsed time: ' + elapsedTime + 'ms');
- sleep(200);
- endTime = new Date();
- setTimeout(count, 100);
- }
- </script>
来源: http://www.phperz.com/article/17/0409/267011.html