三、setInterval()和setTimeout

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

setInterval(function,milliseconds,param1,param2,…)

code/function必需。要调用一个代码串,也可以是一个函数。

milliseconds必须。周期性执行或调用 code/function
之间的时间间隔,以毫秒计。

param1, param2, …可选。 传给执行函数的其他参数(IE9
及其更早版本不支持该参数)。

setInterval(function(){alert(“Hello”)},3000);

语法:setTimeout(code, millisec, args);

clearInterval() 方法用于停止 setInterval() 方法执行的函数代码

myVar=setInterval(“javascript function”,milliseconds);

setTimeout(code, millisec, args);

//code必需。要调用的函数后要执行的 JavaScript 代码串。

//millisec必需。在执行代码前需等待的毫秒数。

//args可选。 传给执行函数的其他参数

myVar=setTimeout(alertFunc,2000,”Runoob”,”Google”);

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

1、setTimeout原理

varstart =newDate();

varend = 0;

setTimeout(function() {  console.log(newDate() – start); }, 500);

while(newDate() – start <= 1000) {}

打印结果 1003

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

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

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

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

浏览器下的javascript

JavaScript引擎是基于事件驱动单线程执行的,JavaScript引擎一直等待着任务队列中任务的到来,然后加以处理,浏览器无论什么时候都只有一个JavaScript线程在运行JavaScript程序。

GUI渲染线程负责渲染浏览器界面,当界面需要重绘(Repaint)或由于某种操作引发回流(Reflow)时,该线程就会执行。但需要注意,GUI渲染线程与JavaScript引擎是互斥的,当JavaScript引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JavaScript引擎空闲时立即被执行。

事件触发线程,当一个事件被触发时,该线程会把事件添加到待处理队列的队尾,等待JavaScript引擎的处理。这些事件可来自JavaScript引擎当前执行的代码块如setTimeout、也可来自浏览器内核的其他线程如鼠标点击、Ajax异步请求等,但由于JavaScript的单线程关系,所有这些事件都得排队等待JavaScript引擎处理(当线程中没有执行任何同步代码的前提下才会执行异步代码)。

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

2、setTimeout的好搭档“0”

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);

};

keydown:用户在键盘上按下某按键是发生。一直按着某按键则会不断触发(opera浏览器除外)。

keypress:用户按下一个按键,并产生一个字符时发生(也就是不管类似shift、alt、ctrl之类的键,就是说用户按了一个能在屏幕上输出字符的按键keypress事件才会触发)。一直按着某按键则会不断触发。

keyup:用户释放某一个按键是触发。

当你往两个表单输入内容时,你会发现未使用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并不会触发。