setTimeout 和 setInterval

特性:
1.由于JavaScript是单线程的(同一时间只能执行一处JavaScript代码),定时器提供了一种跳出限制的方法。(HTML5 WEB worker 产生了多线程)
3.异步处理程序,如用户界面事件和定时器, 在线程中没有代码执行的时候才进行执行,处理程序在执行时必须进行排队,并且一个处理程序并不能中断另外一个处理程序的执行
4.浏览器不会对一个interval处理程序的多个实例进行排队
 
 
延迟参数:
1.不同浏览器, 不同的操作系统,浏览器中的实际最小延迟都是不确定的。 25ms基本都可以达到
2.IE浏览器BUG,当setInterval()设置为0毫秒的延迟时, 该定时器的callback回调只会执行一次, 和使用setTimeout的效果一样
 
setTimeout 和 setInterval 区别:
1.setTimeout的形式 如果上一轮没按预期执行,被延迟了,因为要保证俩轮之间的间隔底线,之后的所有轮都被会延迟,预期的触发点都会调整,前面的异步环节如果被延迟的话,后面的环节也受影响
2.setInterval的形式 如果上一轮没按预期执行,被延迟了,因为所有轮的预期的触发点确定了,所以前面的异步环节如果被延迟的话,后面的环节不受影响
3.setInterval形式, clearInterval的条件, 正是setTimeout继续嵌套的条件的非。也就是 终止间歇调用的条件的非 === 继续超时调用的条件
6.如果一直被延迟,到最后, Interval间隔定时器可能会无延迟执行
7.使用闭包给定时器或间隔定时器传递数据. 现代浏览器中也可以出入参数 例如setTimeout(callback, interval,arg1, arg2)
 
setTimeout嵌套(递归) 和 setInterva 的区别
     1.setTimeout代码中,要前一个callback回调执行结束并延迟10秒(可能更多)以后,才再次执行setTimeout。
     2.第一种的变体首次同步执行,之后异步执行,可用于构建中央定时器(定时器只有一处代码,方便清除定时器)
     2.setInterval()则是每隔10毫秒就尝试执行callback回调, 而不关注上一个callback是何时执行的
setTimeout(function repeatMe() {           
    //some code
    setTimeout(repeatMe, 10)
}, 10)
( function repeatMe(  ) {
    //代码
    setTimeout( repeatMe, 10 )
} )()
setInterval(function() {
    //some code
}, 10)
 
 
应用场景:
1.计算密集型的代码
2.JavaScript动画
3.异步测试组件
 
解决方案: 
1.作为定时器,它可以有效暂停一段JavaScript代码的执行一段时间,定时器还可以将代码的各个部分,分解成不会让浏览器挂掉(或者卡顿)的碎片。我们可以将循环和操作转化为非阻  塞操作
2.同时使用多个定时器(定时器嵌套不算同时使用多个定时器),同时使用多个定时器时的缺陷
     1.定时器通常在JavaScript单线程引擎之外的流程中进行管理的(浏览器的其他线程),所以在有些浏览器的垃圾回收周期比较长
     2.管理成本高
3.中央定时器 (核心:setTimeout连环调用)(不适用setInterval的原因: 根据setInterval的特性,时间间隔和取消执行, 不如setTimeout的连续执行效果好)
 

中央定时器控制的特点
1.每个页面在同一时间只需要运行一个定时器
2.可以根据需要暂停和恢复定时器
3.删除回调函数的过程变得简单
 
 
***************************


//阻塞操作
var tbody = "text/javascript"
for (var i = 0; i < 20000; i++){
var tr = document.getElementsByTagName("tbody")[0]
for (var t = 0; t < 6;t++) {
var td = document.createElement("td")
td.appendChild(document.createTextNode(i + "," + t))
tr.appendChild()
}
tbody.appendChild(tr)
}
// (分时函数)非阻塞的操作 ,原理就是setTimeout的嵌套(递归),附带终止条件。
var rowCount = 20000
var divideInto = 4
var chunkSize = rowCount/divideInto
var iteration = 0
var table = document.getElementsByName("tbody")[0]
setTimeout(function generateRows(){
var base = (chunkSize) * iteration
for (var i = 0; i < chunkSize; i++) {
var tr = document.createElement("tr")
for (var t = 0; t < 6; t++) {
var td = document.createElement("td")
td.appendChild(document.createTextNode((i + base) + "" + t + "," + iteration))
tr.appendChild(td)
}
table.appendChild(tr)
}
iteration++
if (iteration < divideInto) {
setTimeout(generateRows, 0)
}
},0)


//中央定时器控制
//中央控制器对象
var timers = {
timeID: null, // 1.标记非阻塞操作是否已经开启, null为未开启, 否则为已经开启了 2.用于清除定时器
funs: [],

//像函数列表中增加函数
//函数的执行顺序和添加顺序相同
add: function (fn) {
this.funs.push(fn)
},

//开启定时器,分割连续的操作
start: function () {
//此处功能,防止多次调用 start() 造成混乱
if (this.timeID) return
//遍历调用函数列表,并开启下个定时器
(function runNext () {
// 由于循环会修改数组的长度,所以每次比较都要求length的大小
for (var i = 0; i < timers.funs.length; i++) {
//注意是 === ,不显示调用return ,return返回的是 undefined
//如果函数返回false,会从函数列表中移除,以后不会再调用
if (timers.funs[i]() === false) {
timers.funs.splice(i, 1)
//由于数组长度变了,索引退一位
i--;
}
}
//使用的是单一定时器,因为下一行语句是异步调用,不用runNext函数执行完,此语句已经返回了
//所以前一个定时器结束了,下一次定时器开始了
timers.timeID = setTimeout(runNext, 0)
})()
//与此种形式的区别: runNext这种形式的第一轮不异步调用,之后的环节异步调用
// repeatMe这种形式所以的环节都是异步调用
// setTimeout(function repeatMe() {
// //some code
// setTimeout(repeatMe, 10)
// }, 10)
},

//清除下一轮的定时器,上一环的调用才能开始下一环的调用,所以也就代表清除了之后的所以调用
stop: function () {
clearTimeout(this.timeID)
this.timeID = null
}
}

var box = document.getElementById("box"), x = 0, y = 0
timers.add(function () {
box.style.left = x + "px"
if (++x > 50) return false
//等价于
// if (++x <= 50) {
// box.style.left = x + "px"
// }
})

timers.add(function () {
box.style.top = y + "px"
y += 2
if (y > 200) return false
})

timers.start()
***************************
 
 
posted @ 2016-09-03 22:41  阿巴阿巴55996  阅读(161)  评论(0)    收藏  举报