深深探寻javascript定时器,从set提姆eout谈JavaScript运行机制

你会用setTimeout吗

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

正文小编: 伯乐在线 –
唐光尧
。未经小编许可,禁止转发!
迎接加入伯乐在线 专辑撰稿人。

读本里面的set提姆eout

概念很简短
set提姆eout() 方法用于在指定的毫秒数后调用函数或计算表明式。

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

下边一些相应是set提姆eout在豪门心中的规范,因为大家平日使用也不是累累。

只是set提姆eout真的有那么粗略吗?

测试题

一个题材,若是您在一段代码中发现上边内容

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,Fire福克斯中,第一遍配可能给个很大的数字,100ms上下,未来会压缩到细微时间距离,Safari,chrome,opera则多为10ms上下。

地点答案来自《javascript框架设计》

好了,看了上边几个难题是或不是觉得set提姆eout不是想象中那么了。

你应该领会的 set提姆eout 秘密

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) {}

在地点的代码中,定义了一个set提姆eout定时器,延时光阴是500飞秒。

您是否觉得打印结果是: 500

可实际却是出乎你的预料,打印结果是那般的(也许你打印出来会分裂,但必然会高于1000微秒):

亚洲必赢官网 1

那是为毛呢?

究其原因,那是因为
JavaScript是单线程执行的。也就是说,在此外时间点,有且只有一个线程在运作JavaScript程序,不能够等同时候运行多段代码。

再来看看浏览器下的JavaScript。

浏览器的木本是多线程的,它们在根本控制下相互同盟以保全同步,一个浏览器至少落成四个常驻线程:JavaScript引擎线程GUI渲染线程浏览器事件触发线程

  • JavaScript引擎是基于事件驱动单线程执行的,JavaScript引擎平素等候着职责队列中职务的来到,然后加以处理,浏览器无论怎么时候都唯有一个JavaScript线程在运作JavaScript程序。
  • GUI渲染线程担负渲染浏览器界面,当界面须要重绘(Repaint)或是因为某种操作引发回流(Reflow)时,该线程就会履行。但必要留意,GUI渲染线程与JavaScript引擎是排斥的,当JavaScript引擎执行时GUI线程会被挂起,GUI更新会被保留在一个种类中等到JavaScript引擎空闲时及时被执行。
  • 事件触发线程,当一个风浪被触发时,该线程会把事件添加到待处理队列的队尾,等待JavaScript引擎的处理。这个事件可来自JavaScript引擎当前施行的代码块如set提姆eout、也可来自浏览器内核的别样线程如鼠标点击、Ajax异步请求等,但鉴于JavaScript的单线程关系,所有这几个事件都得排队等待JavaScript引擎处理(当线程中从不举办其它共同代码的前提下才会履行异步代码)。

到那里,大家再来回想一下先前时期的例证:

深深探寻javascript定时器,从set提姆eout谈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、set提姆eout的好搭档“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皮秒,若是低于这些值,就会活动扩充,并且在二〇一〇年及今后公布的浏览器中行使同样。

据此说,当我们写为 setTimeout(fn,0)
的时候,实际是兑现插队操作,要求浏览器“尽可能快”的展开回调,可是实际能多快就全盘取决于浏览器了。

setTimeout(fn, 0)有啥用处吧?其实用处就在于大家可以更改义务的履行顺序!因为浏览器会在推行完当前任务队列中的职责,再实践set提姆eout队列中积淀的的职分。

由此设置义务在延迟到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);
 
};

实例:实例

当你往七个表单输入内容时,你会发现未选择set提姆eout函数的只会取得到输入前的始末,而利用set提姆eout函数的则会获得到输入的内容。

那是干什么吧?

因为当按下按键的时候,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、set提姆eout的一部分机密

3.1 set提姆eout中回调函数的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 set提姆eout不止三个参数

俺们都知晓,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);

假使你有问号或指出,欢迎在底下的评论区评论!

打赏接济我写出越来越多好文章,谢谢!

打赏小编

初稿出处: 韩子迟   

javascript单线程

set提姆eout和单线程

上面是自家自己的有些通晓
首先须求留意javascript是单线程的,特点就是便于并发堵塞。若是一段程序处理时间很长,很不难造成整个页面hold住。什么交互都处理不了如何做?

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

地点都是ok的做法,不过set提姆eout也是拍卖那种题材的一把好手。

setTimeout一个很主要的用法就是分片,借使一段程序过大,大家可以拆分成若干细小的块。
例如地点的情景,大家将那一段复杂的逻辑拆分处理,分片塞入队列。那样就是在复杂程序没有处理完时,大家操作页面,也是能获得即便响应的。其实就是将相互插入到了复杂程序中实践。

换一种思路,下面就是拔取set提姆eout落成一种伪八线程的概念。

有个函数库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,大家是伺机完全处理到位在呈现,仍旧利用一个set提姆eout分片,将内容一片一片的断续显示。

实际上set提姆eout给了我们有的是优化交互的上空。

打赏接济我写出越来越多好小说,谢谢!

任选一种支付办法

亚洲必赢官网 2
亚洲必赢官网 3

3 赞 14 收藏 4
评论

从setTimeout说起

妇孺皆知,JavaScript是单线程的编程,什么是单线程,就是说同一时间JavaScript只好进行一段代码,若是那段代码要推行很长日子,那么未来的代码只好尽情地等候它实施完才能有空子执行,不像人一致,人是多线程的,所以你可以一边观察某岛国动作片,一边尽情挥洒汗水。JavaScript单线程机制也是无奈,假诺有七个线程,同时修改某个dom元素,那么到底是听哪个线程的吗?

既然如此已经妇孺皆知JavaScript是单线程的言语,于是大家想方设法要想出JavaScript的异步方案也就可以领略了。比如执行到某段代码,需求是1000ms后调用方法A,JavaScript没有sleep函数能挂起线程一秒啊?如何可以使得代码做到一边等待A方法执行,一边继续执行上面的代码,就好像开了五个线程一般?机制的地理学家们想出了set提姆eout方法。

set提姆eout方法或者我们都早已很熟知了,那么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运行机制了。

JavaScript的单线程,与它的用处有关。作为浏览器脚本语言,JavaScript的紧要用途是与用户互动,以及操作DOM。那决定了它不得不是单线程,否则会带动很复杂的同台难题。比如,假定JavaScript同时有七个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了那些节点,那时浏览器应该以哪个线程为准?所以,为了幸免复杂性,从一出世,JavaScript就是单线程,这一度成了那门语言的着力特征,以后也不会变动。

什么样行使

set提姆eout这么厉害,那么大家是索要在在项目中大量施用啊?
自己那边的视角是非凡不指出,在大家业务中,基本上是不准在工作逻辑中使用set提姆eout的,因为我所看到的大队人马利用方法都是部分题材不好解决,set提姆eout作为一个hack的主意。
譬如说,当一个实例还平素不早先化的前,我们就使用那些实例,错误的解决办法是拔取实例时加个set提姆eout,确保实例先初始化。
何以错误?那里其实就是使用hack的一手
第一是埋下了坑,打乱模块的生命周期
第二是出现难点时,set提姆eout其实是很难调试的。

自己觉着不错的选用方法是,看看生命周期(可参看《关于软件的生命周期
》),把实例化提到使用前举行。

综上,set提姆eout其实想用好仍然很辛苦的,
他更加多的产出是在框架和类库中,例如有些落成Promis的框架,就用上了setTimeout去落成异步。
所以假诺你想去阅读一些源码,想去造一些轮子,set提姆eout仍然必需的工具。

 

打赏扶助自己写出越多好文章,谢谢!

打赏小编

有关小编:TGCode

亚洲必赢官网 4

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

亚洲必赢官网 5

JavaScript运行机制

一段JavaScript代码到底是怎样执行的?阮一峰先生有篇不错的作品(JavaScript
运行机制详解:再谈伊芙nt
Loop),我就不再另行造轮子了;假设觉得太长不看的话,楼主简短地大白话描述下。一段js代码(里面可能带有部分set提姆eout、鼠标点击、ajax等事件),从上到下开端施行,遭遇set提姆eout、鼠标点击等事件,异步执行它们,此时并不会潜移默化代码主体继续往下执行(当线程中绝非履行其它共同代码的前提下才会履行异步代码),一旦异步事件实施完,回调函数重返,将它们按次序加到实施队列中,那时要留意了,设若主体代码没有进行完的话,是永远也不会触发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后响应set提姆eout的回调,接着是一个鼠标点击事件,该事件有个回调(或许是alert一些东西),不可能即时实施(单线程),因为js主体代码还没执行完,所以那个回调被插入执行队列中,等待执行;接着setInterval函数被实施,大家明白,此后每隔10ms都会有回调(尝试)插入队列中,运行到第10ms的时候,set提姆eout函数的回调插入队列。js函数主体运作完后,大概是18ms这么些点,大家发现队列中有个click的callback,还有个setTimeout的callback,于是大家先运行前者,在运行的进度中,setInterval的10ms响应时间也过了,同样回调被插入队列。click的回调运行完,运行set提姆eout的回调,那时又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的认识的姿势不对导致,若是有通晓的情侣还望不吝赐教,相当感激!

简单的讲,定时器仅仅是在未来的某部时刻将代码添加到代码队列中,执行时机是不可能有限协助的。

队列职务

打赏协助自己写出更加多好小说,谢谢!

任选一种支付情势

亚洲必赢官网 7
亚洲必赢官网 8

1 赞 7 收藏 1
评论

setTimeout VS setInterval

之前看到过那样的话,setInterval的职能都能用set提姆eout去完结,想想也对,无穷尽地递归调用set提姆eout不就是setInterval了呢?

JavaScript

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

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

依照前文描述,大家几乎懂了上述setInterval回调函数的施行时间差<=10ms,因为可能会出于线程阻塞,使得一系列的回调全体在排队。用set提姆eout落成的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的回调是同样爱抚的,前一个回调(有没有履行)并不会潜移默化后一个回调(插入队列),而set提姆eout之间的回调是嵌套的,后一个回调是前一个回调的回调(有点绕口令的意思)

单线程就意味着,所有任务需求排队,前一个义务完毕,才会履行后一个职责。即便前一个职分耗时很长,后一个职分就只可以直接等着。

关于作者:唐光尧

亚洲必赢官网 9

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

亚洲必赢官网 10

参考资料

  1. JavaScript 运行机制详解:再谈伊芙nt
    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 收藏
    评论


异步事件驱动

浏览器中很多表现是异步(Asynchronized)的,例如:鼠标点击事件、窗口大小拖拉事件、定时器触发事件、XMLHttpRequest完毕回调等。当一个异步事件时有爆发的时候,它就进去事件队列。浏览器有一个里面大新闻循环,伊芙nt
Loop(事件循环),会轮询大的事件队列并处总管件。例如,浏览器当前正在坚苦处理onclick事件,那时别的一个事变暴发了(如:window
onSize),这么些异步事件就被放入事件队列等待处理,唯有前面的处理达成了,空闲了才会举办那个事件。

Event Loop

JavaScript是单线程的,但浏览器不是单线程的

浏览器至少会有以下部分经过

1.浏览器 GUI 渲染线程

2.JavaScript 引擎线程

3.浏览器定时触发器线程

4.浏览器事件触发线程

5.浏览器 http 异步请求线程

因为 JavaScript
引擎是单线程的,所以代码都是先压到队列,然后由引擎采取先进先出的方法运行。事件处理函数、timer
执行函数也会排到那几个队列中,然后利用一个无穷回圈,不断从队头取出函数执行,那一个就是伊夫nt
Loop。

小结一句话,js是单线程的,可是浏览器是十六线程的,遇到异步的事物都是由浏览器把异步的回调放到伊夫nt
Loop中,js线程不繁忙的时候,再去读取伊夫nt Loop

定时器原理

定时器的用法

setTimeout(fn, delay)

setInterval(fn, delay)

fn是函数也足以是字符串,delay是延迟的光阴,单位是飞秒

有以下要留心的

1.fn固然能够是字符串,可是一向都不推荐这么使用

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

一经精通好了js单线程和伊芙nt loop,定时器的法则也很好了解了

假设设置了定时器,当到了延迟时间,浏览器会把延迟执行的轩然大波放到伊夫nt
loop里面,当岁月到了,如若js线程空闲就会履行了(所以定时器的精度不准呀)

看有小说介绍说set提姆eout和setInterval对函数平昔轮询的差异,代码如下

复制代码 代码如下:

        setTimeout(function(){
            setTimeout(arguments.callee,100)   
        },100)
        setInterval(function(){},1000)

文章大约的情趣是set提姆eout是在回调函数执行后才启动下一遍定时器,所以毫无疑问是有距离的施行,而setInterval是间接都在实施,如若遇上了js线程一直施行,可能就会在伊芙nt
loop里面加四个回调,当js线程不忙的时候,会眨眼之间间举行多个

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

测试代码如下

复制代码 代码如下:

        setInterval(function(){
            xx.innerHTML=xx.innerHTML+1;
        },100);
       
亚洲必赢官网,        for(var i=0;i<6000000;i++){
            xx.offsetWidth
        }

        setTimeout(function(){
            debugger;
        },10)

断点的时候仍然只打印出了1个1

定时器的精度难点

因为js单线程原因,若是遇上繁忙,定时器肯定不准,而且必然是更进一步长的,这一个看似无解啊,无解啊

还有一个精度难点就是不大间隔set提姆eout(fun,0)

在js线程不忙的时候,也无法0秒后旋即执行,总有个小小间隔,每个浏览器还各不均等,这些未做测试

本人看一篇作品中说的是w3c的科班,定时器的很时辰间实施是4ms,找不到出处无从考证呀!!!

定时器相关的一对优化

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

1.比如假若绑定window.onresize,在浏览器缩放的时候,该触发的老大频仍,所以可以延迟执行,当下次履行到的时候clear掉,收缩频仍执行

 伪代码如下

复制代码 代码如下:

    var timer;
    function r(){
        clearTimeout(timer);
        timer = setTimeout(function(){
            //do something
        },150);       
    }

2.在滚动条往下拉的时候也是弹指间,比如图片的lazyload,也应当有一个定时器,幸免过多的计量

3.当有多少个地点须求定时器的时候,可以统一成一个定时器,时间距离以细小的老大为准,然后需要实施的回调函数往数组里面塞,当到了岁月距离,遍历数组执行即可

 一个小demo

复制代码 代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset=”utf-8″ />
    <style>
    .wrap{width:80%; margin: 30px auto; border: 1px solid #ccc;
padding: 20px;}
    .c{border: 1px solid #ccc; height: 30px;margin-bottom: 20px;}
    </style>
</head>
<body>
<div id=”xx”></div>
    <div class=”wrap” >
        <div id=”a1″ class=”c”>0</div>
        <div id=”a2″ class=”c”>0</div>
        <div id=”a3″ class=”c”>0</div>
        <div id=”a4″ class=”c”>0</div>
    </div>
<script
src=”>
    <script type=”text/javascript”>
        var runTime = {
            options  : {
                step : 1000
            },
            callbacks:[],
            addCallbacks : [],
            start : false,
            timer : null,
            extend : function(){
                var target = arguments[0] || {}, i = 1, length =
arguments.length, options;
                if ( typeof target != “object” && typeof target !=
“function” )
                    target = {};
                for ( ; i < length; i++ )
                    if ( (options = arguments[ i ]) != null )
                        for ( var name in options ) {
                            var copy = options[ name ];
                            if ( target === copy )
                                continue;
                            if ( copy !== undefined )
                                target[ name ] = copy;
                        }
                return target;
            },
            init  : function(options){
                $.extend(this,this.options,options||{});
            },
            add : function(fun,options){
                options = options ||{};
                this.addCallbacks.push({
                    fun       : fun,
                    startTime : new Date().getTime(),
                    step      : options.step || this.step,
                    i         : 1
                });
                var self = this;
                if(!this.start){
                    this.callbacks = [fun];
                    this.start = true;
                    this.startTime = new Date().getTime();
                    this.timer = setInterval(function(){
                        self.done();   
                      
                    },this.step);
                }
            },
            done : function(){
                var callbacks = this.callbacks,
                    self   = this,
                    newArr = [];
                $.each(callbacks,function(i,obj){
                    if(obj.step == self.step){
                        obj.fun();
                    }else{                       
                        if(obj.i == obj.step/self.step){
                            if((new
Date().getTime())-obj.startTime>obj.step*2/3){
                                obj.fun();
                            }
                            obj.i = 1;
                        }else{
                            obj.i = obj.i + 1;
                        }
                    }
                });
                $.each(this.addCallbacks,function(i,obj){
                    if(obj.step == self.step){
                        if((new
Date().getTime())-obj.startTime>obj.step*2/3){
                            obj.fun();
                            callbacks.push(obj);
                        }else{
                            newArr.push(obj);
                        }
                    }else{
                        obj.i = obj.i + 1;
                        callbacks.push(obj);
                    }
                });
                this.addCallbacks = newArr;
            },
            clear : function(){
                clearInterval(this.timer);
            }
        }
        runTime.init();

        runTime.add(function(){
            a1.innerHTML = ~~a1.innerHTML+1;
        });

        runTime.add(function(){
            a2.innerHTML = ~~a2.innerHTML+1;
        },{step:2000});

        runTime.add(function(){
            a3.innerHTML = ~~a3.innerHTML+1;
        },{step:4000});
                runTime.add(function(){
            a4.innerHTML = ~~a4.innerHTML+1;
        },{step:8000});
    </script>
</body>
</html>

小伙子伴们是不是对javascript定时器有所驾驭了呢,如有疑问给我留言吗。

您可能感兴趣的小说:

  • JavaScript 定时器
    Set提姆eout之定时刷新窗口和倒闭窗口(代码超简单)
  • 明白javascript定时器中的set提姆eout与setInterval
  • 明亮javascript定时器中的单线程
  • 详解javascript高级定时器
  • javascript中SetInterval与set提姆eout的定时器用法
  • 浅谈Node.js中的定时器
  • JS中自定义定时器让它在某一时刻执行
  • js定时器(执行三次、重复执行)
  • js定时器的运用(实例讲解)
  • JavaScript定时器详解及实例
  • Javascript/Jquery——不难定时器的有余完毕格局
  • 获取关节时,利用js定时器设定时间实施动作
  • JavaScript定时器完成的法则分析
网站地图xml地图