js ajax定时器,js定时器的理解

概念

人们对 JavaScript的定时器存在普遍的误解,认为它们是线程,其实 JavaScript 是运行于单线程的环境中的,而定时器仅仅只是计划代码在未来的某个时间执行。执行时机是不能保证的,因为在页面的生命周期中,不同时间可能有其他代码在控制JavaScript进程。在页面下载完后的代码运行、事件处理程序、Ajax回调函数都必须使用同样的线程来执行。实际上,浏览器负责进行排序,指派某段代码在某个时间点运行 的优先级。

定时器对队列的工作方式是,当特定时间过去后将代码插入。注意,给队列添加代码并不意味着对它立刻执行,而只能表示它会尽快执行。设定一个 150ms 后执行的定时器不代表到了 150ms 代码就立刻 执行,它表示代码会在150ms后被加入到队列中。如果在这个时间点上,队列中没有其他东西,那么这段代码就会被执行,表面上看上去好像代码就在精确指定的时间点上执行了。其他情况下,代码可能明显地等待更长时间才执行。

setTimeout

20ef375341a9c150c8b6564751e5fc9a.png

执行完一套代码后,JavaScript进程返回一段很短的时间,这样页面上的其他处理就可以进行了。由于JavaScript进程会阻塞其他页面处理,所以必须有这些小间隔来防止用户界面被锁定(代码长时间 运行中还有可能出现)。这样设置一个定时器,可以确保在定时器代码执行前至少有一个进程间隔。

setInterval

使用 setInterval()创建的定时器确保了定时器代码规则地插入队列中。这个方式的问题在于,定时器代码可能在代码再次被添加到队列之前还没有完成执行,结果导致定时器代码连续运行好几次, 而之间没有任何停顿。幸好,JavaScript引擎够聪明,能避免这个问题。当使用 setInterval()时,仅当没有该定时器的任何其他代码实例时,才将定时器代码添加到队列中。这确保了定时器代码加入到队列中的最小时间间隔为指定间隔。

这种重复定时器的规则有两个问题:

(1) 某些间隔会被跳过;

(2) 多个定时器的代码执行之间的间隔可能会比预期的小。

为了避免 setInterval()的重复定时器的这 2 个缺点,你可以用如下模式使用链式 setTimeout() 调用。

setTimeout(function(){ //处理中

setTimeout(arguments.callee, interval);//次优选项 可写个function代替

}, interval);

复制代码

这个模式链式调用了setTimeout(),每次函数执行的时候都会创建一个新的定时器。第二个 setTimeout()调用使用了 arguments.callee来获取对当前执行的函数的引用,并为其设置另外一 个定时器。这样做的好处是,在前一个定时器代码执行完之前,不会向队列插入新的定时器代码,确保不会有任何缺失的间隔。而且,它可以保证在下一次定时器代码执行之前,至少要等待指定的间隔,避 免了连续的运行。这个模式主要用于重复定时器,如下例所示。

setTimeout(function(){

var div = document.getElementById("myDiv");

left = parseInt(div.style.left) + 5;

div.style.left = left + "px";

if (left < 200){

setTimeout(arguments.callee, 50);

}

}, 50);

复制代码

requestAnimationFrame

大多数电脑显示器的刷新频率是 60Hz,大概相当于每秒钟重绘 60 次。大多数浏览器都会对 重绘操作加以限制,不超过显示器的重绘频率,因为即使超过那个频率用户体验也不会有提升。

因此,最平滑动画的最佳循环间隔是 1000ms/60,约等于 17ms。以这个循环间隔重绘的动画是最平 滑的,因为这个速度最接近浏览器的最高限速。为了适应 17ms 的循环间隔,多重动画可能需要加以节 制,以便不会完成得太快。

虽然与使用多组setTimeout()的循环方式相比,使用setInterval()的动画循环效率更高,但后者也不是没有问题。无论是setInterval()还是setTimeout()都不十分精确。为它们传入的第二个参数,实际上只是指定了把动画代码添加到浏览器UI线程队列中以等待执行的时间。如果队列前面已经加入了其他任务,那动画代码就要等前面的任务完成后再执行。简言之,以毫秒表示的延迟时间并不代表到时候一定会执行动画代码,而仅代表到时候会把代码添加到任务队列中。如果UI线程繁忙,比如忙于处理用户操作,那么即使把代码加入队列也不会立即执行。

知道什么时候绘制下一帧是保证动画平滑的关键。然而,直至最近,开发人员都没有办法确保浏览 器按时绘制下一帧。

一个非常独特的方案。 CSS变换和动画的优势在于浏览器知道动画什么时候开始,因此会计算出正确的循环间隔,在恰当的时候刷新UI。而对于JavaScript动画,浏览器无从知晓什么时候开始。因此他的方案就是创造一个新方法mozRequestAnimationFrame(),通过它告诉浏览器某些JavaScript代码将要执行动画。这样浏览器可以在运行某些代码后进行适当的优化。

(function(){

function draw(timestamp){

//timestamp 它是一个时间码(从1970 年1月1日起至今的毫秒数),表示下一次重绘的实际发生时间。

//计算两次重绘的时间间隔

var drawStart = (timestamp || Date.now()),

diff = drawStart - startTime; //使用 diff 确定下一步的绘制时间

//把 startTime 重写为这一次的绘制时间 startTime = drawStart;

//重绘 UI

requestAnimationFrame(draw);

}

var requestAnimationFrame = window.requestAnimationFrame ||

window.mozRequestAnimationFrame ||

window.webkitRequestAnimationFrame ||

window.msRequestAnimationFrame,

startTime = window.mozAnimationStartTime || Date.now();

})();

复制代码

疑问?

1.setInterval 与 setTimeout 模拟的setInterval有什么区别?

答:

setInterval如下:

556b1f091d3c4ca5ec06591dadd7224f.png

setInterval(() => {

//定时器代码

}, 200);

复制代码

每200ms向进程插入一次定时器代码,在第5ms,205ms,405ms处都插入了定时器代码,由于这样的一条规则:

当使用 setInterval()时,仅 当没有该定时器的任何其他代码实例时,才将定时器代码添加到队列中。

所以第5ms处,205ms都成功将定时器代码插入js进程中,但是第405ms处由于正在执行定时器代码故插入失败。使这个 间隔被跳过 ,同时执行完第一次定时器代码后紧接着执行了第二次定时器代码,使 多个定时器的代码执行之间的间隔可能会比预期的小。

使用setTimeout

setTimeout(function(){

//定时器代码

setTimeout(arguments.callee, interval);

}, interval);

复制代码

这个模式链式调用了setTimeout(),每次函数执行的时候都会创建一个新的定时器。第二个setTimeout()调用使用了arguments.callee 来获取对当前执行的函数的引用,并为其设置另外一个定时器。这样做的好处是,在前一个定时器代码执行完之前,不会向队列插入新的定时器代码,确保不会有任何缺失的间隔。而且,它可以保证在下一次定时器代码执行之前,至少要等待指定的间隔,避 免了连续的运行。

2.如下代码的 clearTimeout(s)是否可以清楚定时器。

var i = 0

var s = setTimeout(function(){

add()

},300)

function add(){

i++

console.log(123);

console.log(i);

if(i>20){

clearTimeout(s)

}else{

setTimeout(function(){

add()

},300)

}

}

复制代码

答:可

3.arguments.callee 是什么意思?

arguments.callee 属性包含当前正在执行的函数。

callee 是 arguments对象的一个属性。它可以用于引用该函数的函数体内当前正在执行的函数。这在函数的名称是未知时很有用,例如在没有名称的函数表达式 (也称为“匿名函数”)内。

警告:在严格模式下,第5版 ECMAScript (ES5) 禁止使用 arguments.callee()。当一个函数必须调用自身的时候, 避免使用 arguments.callee(), 通过要么给函数表达式一个名字,要么使用一个函数声明.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值