【美高梅开户网址】从set提姆eout谈JavaScript运行机制,深入探寻javascript定时器

你会用setTimeout吗

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

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

读本里面的set提姆eout

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

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

地点一些应当是setTimeout在豪门心中的榜样,因为大家平日使用也不是诸多。

唯独set提姆eout真的有那么粗略吗?

测试题

【美高梅开户网址】从set提姆eout谈JavaScript运行机制,深入探寻javascript定时器。一个难题,即使你在一段代码中发觉上面内容

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框架设计》

好了,看了上面多少个难点是还是不是觉得setTimeout不是想象中那么了。

你应有清楚的 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引擎处理(当线程中绝非执行别的共同代码的前提下才会实施异步代码)。

到此地,大家再来回看一下最初的事例:

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)有何样用处吧?其实用处就在于大家可以变更职分的推行种种!因为浏览器会在推行完当前职分队列中的任务,再举行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);
 
};

实例:实例

当您往七个表单输入内容时,你会意识未使用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也是处理这种难题的一把好手。

set提姆eout一个很紧要的用法就是分片,假使一段程序过大,大家得以拆分成若干细小的块。
比如说地点的境况,大家将那一段复杂的逻辑拆分处理,分片塞入队列。那样就是在复杂程序没有拍卖完时,大家操作页面,也是能获得固然响应的。其实就是将相互插入到了复杂程序中实施。

换一种思路,上边就是使用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,大家是等待完全处理完了在突显,仍旧选用一个setTimeout分片,将内容一片一片的断续展现。

实质上set提姆eout给了大家很多优化交互的长空。

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

任选一种支付情势

美高梅开户网址 2
美高梅开户网址 3

3 赞 14 收藏 4
评论

从setTimeout说起

眼看,JavaScript是单线程的编程,什么是单线程,就是说同一时间JavaScript只能执行一段代码,假若那段代码要进行很长日子,那么之后的代码只可以尽情地守候它执行完才能有时机执行,不像人平等,人是二十多线程的,所以您可以一边观察某岛国动作片,一边尽情挥洒汗水。JavaScript单线程机制也是无奈,如若有多少个线程,同时修改某个dom元素,那么到底是听哪个线程的呢?

既是已经显著JavaScript是单线程的语言,于是我们想方设法要想出JavaScript的异步方案也就可以清楚了。比如执行到某段代码,需要是1000ms后调用方法A,JavaScript没有sleep函数能挂起线程一秒啊?怎么样可以使得代码做到一边等待A方法执行,一边继续执行下边的代码,如同开了三个线程一般?机制的数学家们想出了setTimeout方法。

set提姆eout方法恐怕我们都已经很熟练了,那么set提姆eout(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的框架,就用上了set提姆eout去落到实处异步。
之所以一旦你想去阅读一些源码,想去造一些轱辘,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的重点代码,在履行进程中,先触发了一个set提姆eout函数,代码继续执行,只等10ms后响应set提姆eout的回调,接着是一个鼠标点击事件,该事件有个回调(或许是alert一些东西),不可以立时执行(单线程),因为js主体代码还没实施完,所以那些回调被插入执行队列中,等待执行;接着setInterval函数被实践,大家驾驭,此后每隔10ms都会有回调(尝试)插入队列中,运行到第10ms的时候,set提姆eout函数的回调插入队列。js函数主体运作完后,几乎是18ms那几个点,我们发现队列中有个click的callback,还有个set提姆eout的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去达成,想想也对,无穷尽地递归调用setTimeout不就是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)

小说差不多的意味是setTimeout是在回调函数执行后才启动下两次定时器,所以一定是有距离的执行,而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地图