未经作者许可必威手机官网:,禁止转载

你会用setTimeout吗

2016/03/22 · JavaScript · 1 评论 · settimeout

本文作者: 伯乐在线 - 唐光尧 。未经作者许可,禁止转载!
欢迎加入伯乐在线 专栏作者。

教科书里面的setTimeout

定义很简单
setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式。

广泛应用场景
定时器,轮播图,动画效果,自动滚动等等

上面一些应该是setTimeout在大家心中的样子,因为我们平常使用也不是很多。

但是setTimeout真的有那么简单吗?

测试题

一个题目,如果你在一段代码中发现下面内容

var startTime = new Date(); setTimeout(function () { console.log(new Date() - startTime); }, 100)

1
2
3
4
var startTime = new Date();
setTimeout(function () {
    console.log(new Date() - startTime);
}, 100)

请问最后打印的是多少?
我觉得正确答案是,取决于后面同步执行的js需要占用多少时间。
MAX(同步执行的时间, 100)

再加一个题目,只有下面代码

setTimeout(function () { func1(); }, 0) func2();

1
2
3
4
setTimeout(function () {
    func1();
}, 0)
func2();

func1和func2谁会先执行?

这个答案应该比较简单,func2先执行,func1后面执行。

再来一题

setTimeout(function () { func1() }, 0)

1
2
3
setTimeout(function () {
    func1()
}, 0)

setTimeout(function () { func1() })

1
2
3
setTimeout(function () {
    func1()
})

有什么差别?

0秒延迟,此回调将会放到一个能立即执行的时段进行触发。javascript代码大体上是自顶向下的,但中间穿插着有关DOM渲染,事件回应等异步代码,他们将组成一个队列,零秒延迟将会实现插队操作。
不写第二个参数,浏览器自动配置时间,在IE,FireFox中,第一次配可能给个很大的数字,100ms上下,往后会缩小到最小时间间隔,Safari,chrome,opera则多为10ms上下。

上面答案来自《javascript框架设计》

好了,看了上面几个题目是不是感觉setTimeout不是想象中那样了。

你应该知道的 setTimeout 秘密

2017/01/11 · JavaScript · 4 评论 · Javascript, settimeout

本文作者: 伯乐在线 - TGCode 。未经作者许可,禁止转载!
欢迎加入伯乐在线 专栏作者。

计时器setTimeout是我们经常会用到的,它用于在指定的毫秒数后调用函数或计算表达式。

语法:

setTimeout(code, millisec, args);

1
setTimeout(code, millisec, args);

注意:如果code为字符串,相当于执行eval()方法来执行code。

当然,这一篇文章并不仅仅告诉你怎么用setTimeout,而且理解其是如何执行的。

1、setTimeout原理

先来看一段代码:

var start = new Date();   var end = 0;   setTimeout(function() {      console.log(new Date() - start);   },  500);   while (new Date() - start <= 1000) {}

1
2
3
4
5
6
7
8
9
10
11
var start = new Date();  
 
var end = 0;  
 
setTimeout(function() {   
 
  console.log(new Date() - start);  
 
},  500);  
 
while (new Date() - start <= 1000) {}

在上面的代码中,定义了一个setTimeout定时器,延时时间是500毫秒。

你是不是觉得打印结果是: 500

可事实却是出乎你的意料,打印结果是这样的(也许你打印出来会不一样,但肯定会大于1000毫秒):

必威手机官网 1

这是为毛呢?

究其原因,这是因为 JavaScript是单线程执行的。也就是说,在任何时间点,有且只有一个线程在运行JavaScript程序,无法同一时候运行多段代码。

再来看看浏览器下的JavaScript。

浏览器的内核是多线程的,它们在内核控制下相互配合以保持同步,一个浏览器至少实现三个常驻线程:JavaScript引擎线程GUI渲染线程浏览器事件触发线程

  • JavaScript引擎是基于事件驱动单线程执行的,JavaScript引擎一直等待着任务队列中任务的到来,然后加以处理,浏览器无论什么时候都只有一个JavaScript线程在运行JavaScript程序。
  • GUI渲染线程负责渲染浏览器界面,当界面需要重绘(Repaint)或由于某种操作引发回流(Reflow)时,该线程就会执行。但需要注意,GUI渲染线程与JavaScript引擎是互斥的,当JavaScript引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JavaScript引擎空闲时立即被执行。
  • 事件触发线程,当一个事件被触发时,该线程会把事件添加到待处理队列的队尾,等待JavaScript引擎的处理。这些事件可来自JavaScript引擎当前执行的代码块如setTimeout、也可来自浏览器内核的其他线程如鼠标点击、Ajax异步请求等,但由于JavaScript的单线程关系,所有这些事件都得排队等待JavaScript引擎处理(当线程中没有执行任何同步代码的前提下才会执行异步代码)。

到这里,我们再来回顾一下最初的例子:

var start = new Date();   var end = 0;   setTimeout(function() {      console.log(new Date() - start);   },  500);   while (new Date() - start <= 1000) {}

1
2
3
4
5
6
7
8
9
10
11
var start = new Date();  
 
var end = 0;  
 
setTimeout(function() {   
 
  console.log(new Date() - start);  
 
},  500);  
 
while (new Date() - start <= 1000) {}

虽然setTimeout的延时时间是500毫秒,可是由于while循环的存在,只有当间隔时间大于1000毫秒时,才会跳出while循环,也就是说,在1000毫秒之前,while循环都在占据着JavaScript线程。也就是说,只有等待跳出while后,线程才会空闲下来,才会去执行之前定义的setTimeout

最后 ,我们可以总结出,setTimeout只能保证在指定的时间后将任务(需要执行的函数)插入任务队列中等候,但是不保证这个任务在什么时候执行。一旦执行javascript的线程空闲出来,自行从队列中取出任务然后执行它。

因为javascript线程并没有因为什么耗时操作而阻塞,所以可以很快地取出排队队列中的任务然后执行它,也是这种队列机制,给我们制造一个异步执行的假象。

2、setTimeout的好搭档“0”

也许你见过下面这一段代码:

setTimeout(function(){   // statement }, 0);

1
2
3
4
5
setTimeout(function(){
 
  // statement
 
}, 0);

上面的代码表示立即执行。

本意是立刻执行调用函数,但事实上,上面的代码并不是立即执行的,这是因为setTimeout有一个最小执行时间,当指定的时间小于该时间时,浏览器会用最小允许的时间作为setTimeout的时间间隔,也就是说即使我们把setTimeout的延迟时间设置为0,被调用的程序也没有马上启动。

不同的浏览器实际情况不同,IE8和更早的IE的时间精确度是15.6ms。不过,随着HTML5的出现,在高级版本的浏览器(Chrome、ie9+等),定义的最小时间间隔是不得低于4毫秒,如果低于这个值,就会自动增加,并且在2010年及之后发布的浏览器中采取一致。

所以说,当我们写为 setTimeout(fn,0) 的时候,实际是实现插队操作,要求浏览器“尽可能快”的进行回调,但是实际能多快就完全取决于浏览器了。

setTimeout(fn, 0)有什么用处呢?其实用处就在于我们可以改变任务的执行顺序!因为浏览器会在执行完当前任务队列中的任务,再执行setTimeout队列中积累的的任务。

通过设置任务在延迟到0s后执行,就能改变任务执行的先后顺序,延迟该任务发生,使之异步执行。

来看一个网上很流行的例子:

document.querySelector('#one input').onkeydown = function() {      document.querySelector('#one span').innerHTML = this.value;    };    document.querySelector('#second input').onkeydown = function() {      setTimeout(function() {        document.querySelector('#second span').innerHTML = document.querySelector('#second input').value;   }, 0); };

1
2
3
4
5
6
7
8
9
10
11
12
13
document.querySelector('#one input').onkeydown = function() {   
 
  document.querySelector('#one span').innerHTML = this.value;   
 
};   
 
document.querySelector('#second input').onkeydown = function() {   
 
  setTimeout(function() {   
 
    document.querySelector('#second span').innerHTML = document.querySelector('#second input').value;   }, 0);
 
};

实例:实例

当你往两个表单输入内容时,你会发现未使用setTimeout函数的只会获取到输入前的内容,而使用setTimeout函数的则会获取到输入的内容。

这是为什么呢?

因为当按下按键的时候,JavaScript 引擎需要执行 keydown 的事件处理程序,然后更新文本框的 value 值,这两个任务也需要按顺序来,事件处理程序执行时,更新 value值(是在keypress后)的任务则进入队列等待,所以我们在 keydown 的事件处理程序里是无法得到更新后的value的,而利用 setTimeout(fn, 0),我们把取 value 的操作放入队列,放在更新 value 值以后,这样便可获取出文本框的值。

未使用setTimeout函数,执行顺序是:onkeydown => onkeypress => onkeyup

使用setTimeout函数,执行顺序是:onkeydown => onkeypress => function => onkeyup

虽然我们可以使用keyup来替代keydown,不过有一些问题,那就是长按时,keyup并不会触发。

长按时,keydown、keypress、keyup的调用顺序:

keydown keypress keydown keypress ... keyup

1
2
3
4
5
6
7
8
9
10
11
keydown
 
keypress
 
keydown
 
keypress
 
...
 
keyup

也就是说keyup只会触发一次,所以你无法用keyup来实时获取值。

我们还可以用setImmediate()来替代setTimeout(fn,0)

if (!window.setImmediate) {      window.setImmediate = function(func, args){        return window.setTimeout(func, 0, args);      };      window.clearImmediate = window.clearTimeout;   }

1
2
3
4
5
6
7
8
9
10
11
if (!window.setImmediate) {   
 
  window.setImmediate = function(func, args){   
 
    return window.setTimeout(func, 0, args);   
 
  };   
 
  window.clearImmediate = window.clearTimeout;  
 
}

setImmediate()方法用来把一些需要长时间运行的操作放在一个回调函数里,在浏览器完成后面的其他语句后,就立刻执行这个回调函数,必选的第一个参数func,表示将要执行的回调函数,它并不需要时间参数。

注意:目前只有IE10支持此方法,当然,在Nodejs中也可以调用此方法。

3、setTimeout的一些秘密

3.1 setTimeout中回调函数的this

由于setTimeout()方法是浏览器 window 对象提供的,因此第一个参数函数中的this其实是指向window对象,这跟变量的作用域有关。

看个例子:

var a = 1;    var obj = {      a: 2,      test: function() {        setTimeout(function(){          console.log(this.a);        }, 0);      }    };    obj.test();  //  1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var a = 1;   
 
var obj = {   
 
  a: 2,   
 
  test: function() {   
 
    setTimeout(function(){   
 
      console.log(this.a);   
 
    }, 0);   
 
  }   
 
};   
 
obj.test();  //  1

不过我们可以通过使用bind()方法来改变setTimeout回调函数里的this

var a = 1;    var obj = {      a: 2,      test: function() {        setTimeout(function(){          console.log(this.a);        }.bind(this), 0);      }    };    obj.test();  //  2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var a = 1;   
 
var obj = {   
 
  a: 2,   
 
  test: function() {   
 
    setTimeout(function(){   
 
      console.log(this.a);   
 
    }.bind(this), 0);   
 
  }   
 
};   
 
obj.test();  //  2

相关文章:JS中的call、apply、bind方法

3.2 setTimeout不止两个参数

我们都知道,setTimeout的第一个参数是要执行的回调函数,第二个参数是延迟时间(如果省略,会由浏览器自动设置。在IE,FireFox中,第一次配可能给个很大的数字,100ms上下,往后会缩小到最小时间间隔,Safari,chrome,opera则多为10ms上下。)

其实,setTimeout可以传入第三个参数、第四个参数….,它们表示神马呢?其实是用来表示第一个参数(回调函数)传入的参数。

setTimeout(function(a, b){      console.log(a);   // 3   console.log(b);   // 4 },0, 3, 4);

1
2
3
4
5
6
7
setTimeout(function(a, b){   
 
  console.log(a);   // 3
 
  console.log(b);   // 4
 
},0, 3, 4);

如果你有疑问或建议,欢迎在下面的评论区评论!

打赏支持我写出更多好文章,谢谢!

打赏作者

从setTimeout说起

众所周知,JavaScript是单线程的编程,什么是单线程,就是说同一时间JavaScript只能执行一段代码,如果这段代码要执行很长时间,那么之后的代码只能尽情地等待它执行完才能有机会执行,不像人一样,人是多线程的,所以你可以一边观看某岛国动作片,一边尽情挥洒汗水。JavaScript单线程机制也是迫不得已,假设有多个线程,同时修改某个dom元素,那么到底是听哪个线程的呢?

既然已经明确JavaScript是单线程的语言,于是我们想方设法要想出JavaScript的异步方案也就可以理解了。比如执行到某段代码,需求是1000ms后调用方法A,JavaScript没有sleep函数能挂起线程一秒啊?如何能够使得代码做到一边等待A方法执行,一边继续执行下面的代码,仿佛开了两个线程一般?机制的科学家们想出了setTimeout方法。

setTimeout方法想必大家都已经很熟悉了,那么setTimeout(function(){..}, a)真的是ams后执行对应的回调吗?

JavaScript

setTimeout(function() { console.log('hello world'); }, 1000); while(true) {};

1
2
3
4
5
setTimeout(function() {
  console.log('hello world');
}, 1000);
 
while(true) {};

1s中之后,控制台并没有像预料中的一样输出字符串,而网页标签上的圈圈一直转啊转,掐指一算,可能陷入while(true){}的死循环中了,可是为什么呢?虽然会陷入死循环可是也得先输出字符串啊!这就要扯到JavaScript运行机制了。

由于不是很了解浏览器的内部执行策略,本文只能是通过前端一些测试依稀猜测些结论:
1)测试举例 做了两个例子:
1-1)脚本在页面中直接执行,通过刷新看结果

2.fn里面的函数如果有this,执行的时候this会指向到window上面去

关于作者:唐光尧

必威手机官网 2

百度凤巢FE 个人主页 · 我的文章 · 2 ·     

必威手机官网 3

打赏支持我写出更多好文章,谢谢!

任选一种支付方式

必威手机官网 4 必威手机官网 5

3 赞 14 收藏 4 评论

JavaScript运行机制

一段JavaScript代码到底是如何执行的?阮一峰老师有篇不错的文章(JavaScript 运行机制详解:再谈Event Loop),我就不再重复造轮子了;如果觉得太长不看的话,楼主简短地大白话描述下。一段js代码(里面可能包含一些setTimeout、鼠标点击、ajax等事件),从上到下开始执行,遇到setTimeout、鼠标点击等事件,异步执行它们,此时并不会影响代码主体继续往下执行(当线程中没有执行任何同步代码的前提下才会执行异步代码),一旦异步事件执行完,回调函数返回,将它们按次序加到执行队列中,这时要注意了,如果主体代码没有执行完的话,是永远也不会触发callback的,这也就是上面的一段代码导致浏览器假死的原因(主体代码中的while(true){}还没执行完)。

网上还有一篇流传甚广的文章(猛戳How JavaScript Timers Work),文章里有张很好的图,我把它盗过来了。必威手机官网 6

文章里没有针对这幅图的代码,为了能更好的说明流程,我尝试着给出代码:

JavaScript

// some code setTimeout(function() { console.log('hello'); }, 10); // some code document.getElementById('btn').click(); // some code setInterval(function() { console.log('world'); }, 10); // some code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// some code
 
setTimeout(function() {
  console.log('hello');
}, 10);
 
// some code
 
document.getElementById('btn').click();
 
// some code
 
setInterval(function() {
  console.log('world');
}, 10);
 
// some code

我们开始执行代码。第一块代码大概执行了18ms,也就是JavaScript的主体代码,在执行过程中,先触发了一个setTimeout函数,代码继续执行,只等10ms后响应setTimeout的回调,接着是一个鼠标点击事件,该事件有个回调(或许是alert一些东西),不能立即执行(单线程),因为js主体代码还没执行完,所以这个回调被插入执行队列中,等待执行;接着setInterval函数被执行,我们知道,此后每隔10ms都会有回调(尝试)插入队列中,运行到第10ms的时候,setTimeout函数的回调插入队列。js函数主体运行完后,大概是18ms这个点,我们发现队列中有个click的callback,还有个setTimeout的callback,于是我们先运行前者,在运行的过程中,setInterval的10ms响应时间也过了,同样回调被插入队列。click的回调运行完,运行setTimeout的回调,这时又10ms过去了,setInterval又产生了回调,但是这个回调被抛弃了,之后发生的事大家都一目了然了。

这里有一点我不太明白,就是关于interval回调的drop。按照How JavaScript Timers Work里的说法是,如果等待队列里已经有同一个interval函数的回调了,将不会有相同的回调插入等待队列。

“Note that while mouse click handler is executing the first interval callback executes. As with the timer its handler is queued for later execution. However, note that when the interval is fired again (when the timer handler is executing) this time that handler execution is dropped. If you were to queue up all interval callbacks when a large block of code is executing the result would be a bunch of intervals executing with no delay between them, upon completion. Instead browsers tend to simply wait until no more interval handlers are queued (for the interval in question) before queuing more.”

查到一篇前辈的文章Javascript定时器学习笔记,里面说“为了确保定时器代码插入到队列总的最小间隔为指定时间。当使用setInterval()时,仅当没有该定时器的任何其他代码实例时,才能将定时器代码添加到代码队列中”。但是我自己实践了下觉得可能并非如此:

JavaScript

var startTime = +new Date; var count = 0; var handle = setInterval(function() { console.log('hello world'); count++; if(count === 1000) clearInterval(handle); }, 10); while(+new Date - startTime < 10 * 1000) {};

1
2
3
4
5
6
7
8
9
var startTime = +new Date;
var count = 0;
var handle = setInterval(function() {
  console.log('hello world');
  count++;
  if(count === 1000) clearInterval(handle);
}, 10);
 
while(+new Date - startTime < 10 * 1000) {};

按照上文的说法,由于while对线程的“阻塞”,使得相同的setInterval的回调不能加在等待队列中,但是实际在chrome和ff的控制台都输出了1000个hello world的字符串,我也去原文博主的文章下留言询问了下,暂时还没答复我;也可能是我对setInterval的认识的姿势不对导致,如果有知道的朋友还望不吝赐教,万分感激!

总之,定时器仅仅是在未来的某个时刻将代码添加到代码队列中,执行时机是不能保证的。

测试结果:  
  在ie各个版本浏览器下,得到的alert结果大体为:5左后,偶尔有大值;
  chrome19,基本为2,偶尔为3
  firefox12,基本为1,0,2,但是偶尔也有13左右的值
  safari5.1,基本为1,偶尔为2和3
  opera11.5,基本为4,3,,但是偶尔有12左右的值。
 
  以上测试,均在打开多个干扰复杂页面的标签、单个标签中测试。结果差不多。
2)说明什么? 
  其实也得不到什么结论,但是测试结果基本反映了当前流行浏览器js脚本的效率排名。
  究其原因,可能得出一些印证:
  2-1)由于js的主执行线程为单线程,所以此值肯定一般大于0,setTimeout的执行时间点只是加入js主执行队列中的时间点,至于什么时候执行,是由js引擎线程按顺序执行的队列来决定。此结论在很多处说到。可自行查阅( 如:JavaScript可否多线程? 深入理解JavaScript定时机制);
  此结论也印证很火时候用setTimeout做动画不流畅的原因等。
  顺便在此贴出背光的一副图很能说明问题:

经过测试发现无论在ie,ff,chrome,Opera,Safari下,setInterval都是按一定间隔来的

如何使用

setTimeout这么厉害,那么我们是需要在在项目中大量使用吗?
我这边的观点是非常不建议,在我们业务中,基本上是禁止在业务逻辑中使用setTimeout的,因为我所看到的很多使用方式都是一些问题不好解决,setTimeout作为一个hack的方式。
例如,当一个实例还没有初始化的前,我们就使用这个实例,错误的解决办法是使用实例时加个setTimeout,确保实例先初始化。
为什么错误?这里其实就是使用hack的手段
第一是埋下了坑,打乱模块的生命周期
第二是出现问题时,setTimeout其实是很难调试的。

我认为正确的使用方式是,看看生命周期(可参考《关于软件的生命周期 》),把实例化提到使用前执行。

综上,setTimeout其实想用好还是很困难的, 他更多的出现是在框架和类库中,例如一些实现Promis的框架,就用上了setTimeout去实现异步。
所以假如你想去阅读一些源码,想去造一些轮子,setTimeout还是必不可少的工具。

 

打赏支持我写出更多好文章,谢谢!

打赏作者

关于作者:TGCode

必威手机官网 7

路途虽远,无所畏 个人主页 · 我的文章 · 9 ·    

必威手机官网 8

setTimeout VS setInterval

以前看到过这样的话,setInterval的功能都能用setTimeout去实现,想想也对,无穷尽地递归调用setTimeout不就是setInterval了吗?

JavaScript

setInterval(function() { // some code }, 10);

1
2
3
setInterval(function() {
  // some code
}, 10);

根据前文描述,我们大概懂了以上setInterval回调函数的执行时间差<=10ms,因为可能会由于线程阻塞,使得一系列的回调全部在排队。用setTimeout实现的setInterval效果呢?

JavaScript

// 1 function func() { setTimeout(function() { // some code func(); }, 10); } func(); // 2 setTimeout(function() { // some code setTimeout(arguments.callee, 1000); }, 10);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 1
function func() {
  setTimeout(function() {
    // some code
    func();
  }, 10);
}
 
func();
 
// 2
setTimeout(function() {
  // some code
  setTimeout(arguments.callee, 1000);
}, 10);

很显然两个回调之间的间隔是>10ms的,因为前面一个回调在队列中排队,如果没有等到,是不会执行下面的回调的,而>10ms是因为回调中的代码也要执行时间。换句话说,setInterval的回调是并列的,前一个回调(有没有执行)并不会影响后一个回调(插入队列),而setTimeout之间的回调是嵌套的,后一个回调是前一个回调的回调(有点绕口令的意思)

3-2)测试偶尔的很大值,也有可能是js主执行线程中做了其他事情,如GC等。因为大值重复出现几率很少。
 
总结:其实我是没有得出结论,只是好奇,然后猜测,看看可能是情况和结果,希望大家批评指正。或者有结论的答复我。
另外:setTimout函数中第二个参数如果为负数,则和0具有一样的效果,如果setTimeout(function(){console.log('test')},-100);等同于setTimeout(function(){console.log('test')},0)。
我以为会报错,结果所有浏览器都没有报错。

fn是函数也可以是字符串,delay是延迟的时间,单位是毫秒

setTimeout和单线程

下面是我自己的一些理解
首先需要注意javascript是单线程的,特点就是容易出现阻塞。如果一段程序处理时间很长,很容易导致整个页面hold住。什么交互都处理不了怎么办?

简化复杂度?复杂逻辑后端处理?html5的多线程?

上面都是ok的做法,但是setTimeout也是处理这种问题的一把好手。

setTimeout一个很关键的用法就是分片,如果一段程序过大,我们可以拆分成若干细小的块。
例如上面的情况,我们将那一段复杂的逻辑拆分处理,分片塞入队列。这样即使在复杂程序没有处理完时,我们操作页面,也是能得到即使响应的。其实就是将交互插入到了复杂程序中执行。

换一种思路,上面就是利用setTimeout实现一种伪多线程的概念。

有个函数库Concurrent.Thread.js 就是实现js的多线程的。

一个简单使用的例子,引入Concurrent.Thread.js

Concurrent.Thread.create(function(){ for (var i = 0;i<1000000;i++) { console.log(i); }; }); $('#test').click(function () { alert(1); });

1
2
3
4
5
6
7
8
Concurrent.Thread.create(function(){
    for (var i = 0;i<1000000;i++) {
        console.log(i);
    };
});
$('#test').click(function  () {
    alert(1);
});

虽然有个巨大的循环,但是这时不妨碍你去触发alert();

是不是很厉害~

还有一种场景,当我们需要渲染一个很复杂的DOM时,例如table组件,复杂的构图等等,假如整个过程需要3s,我们是等待完全处理完成在呈现,还是使用一个setTimeout分片,将内容一片一片的断续呈现。

其实setTimeout给了我们很多优化交互的空间。

原文出处: 韩子迟   

<!DOCTYPE HTML>
<HTML>
<HEAD>
<script type="text/javascript">
function test(){
var t=new Date;
setTimeout(function(){
alert('cost time:'+(new Date-t))
},0);
}
</script>
</HEAD>
<BODY>
<div onclick='test()' id="div1" style="position:relative;width:200px;height:200px;background-color:green;left:100px;top:100px;">
</div>
</BODY>
</HTML>

断点的时候还是只打印出了1个1

打赏支持我写出更多好文章,谢谢!

任选一种支付方式

必威手机官网 9 必威手机官网 10

1 赞 7 收藏 1 评论

参考资料

  1. JavaScript 运行机制详解:再谈Event Loop
  2. 深入理解JavaScript定时机制
  3. How JavaScript Timers Work

 

2015.7.1修正

经验证,确实是楼主对于setInterval认识的姿势有误,也对得起两个反对的差评,当使用setInterval()时,仅当没有该定时器的任何其他代码实例时,才能将定时器代码添加到代码队列中。

楼主的示例代码,正如评论中说的一样,无论有无阻塞,都会运行1000次。代码修改如下:

JavaScript

var startTime = +new Date; var handle = setInterval(function() { console.log('hello world'); }, 3000); while(+new Date - startTime < 10 * 1000) {};

1
2
3
4
5
6
7
var startTime = +new Date;
 
var handle = setInterval(function() {
  console.log('hello world');
}, 3000);
 
while(+new Date - startTime < 10 * 1000) {};

如果按照之前的认识,在while阻塞过程中,setInterval应该插入了3个回调函数,而当while运行完后,控制台应该打出连续3个字符串,但是并没有,说明确实只加入了一个回调函数,其他两个被drop了。而木的树举了个更好的例子,详见Javascript定时器学习笔记评论部分的第二个示例代码。

所以确实在使用setInterval时:

  1. 某些间隔会被跳过
  2. 多个定时器的代码执行之间的间隔可能会比预期的小(当前的setInterval回调正在执行,后一个添加)

    1 赞 3 收藏 评论

必威手机官网 11

队列任务

1-2)通过点击div看结果

        setInterval(function(){
            xx.innerHTML=xx.innerHTML+1;
        },100);
       
        for(var i=0;i<6000000;i++){
            xx.offsetWidth
        }

复制代码 代码如下:

定时器原理

测试结果: 
 
  在ie各个版本浏览器下,得到的alert结果大体为:14左后,区间为8~21毫秒之间;
  chrome19,基本为1,区间为1~5之间,但是偶尔会是15左右
  firefox12,基本为3,区间为2~7之间,但是偶尔也有15左右的值
  safari5.1,基本为4,区间为1~7之间,但是偶尔也有15左右的值
  opera11.5,基本为5,区间为2~8之间,但是偶尔有很大值

setTimeout(fn, delay)

您可能感兴趣的文章:

  • setTimeout函数兼容各主流浏览器运行执行效果实例
  • JQuery中SetTimeOut传参问题探讨
  • 5秒后跳转效果(setInterval/SetTimeOut)
  • Jquery中使用setInterval和setTimeout的方法
  • jQuery中setTimeout的几种使用方法小结
  • jQuery setTimeout()函数使用方法
  • Jquery倒数计时按钮setTimeout的实例代码

复制代码 代码如下:

复制代码 代码如下:

浏览器至少会有以下一些进程

<!DOCTYPE HTML>
<HTML>
<HEAD>
<script type="text/javascript">
var t=new Date;
setTimeout(function(){
alert('cost time:'+(new Date-t))
},0);
</script>
</HEAD>
<BODY>
</BODY>
</HTML>

定时器的用法

在做定时器的时候还是可以有一些优化的

本文由必威发布于必威-前端,转载请注明出处:未经作者许可必威手机官网:,禁止转载

相关阅读