- 所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)
- 主线程外,还有一个“任务队列”(task queue)。只要异步任务有了结果,就在“任务队列”中放置一个事件,同时执行相应代码。
- 定时器对“任务队列”的工作方式是,当特定时间过去后将代码插入。
- 指定的时间间隔表示何时将定时器的代码添加到队列中,而不是何时实际执行代码。
1. 重复的定时器
- 当使用
setIntervel()
时,仅当没有该定时器的任何其他代码实例时,才将定时器代码添加到“任务队列”。 - 有两个问题:
- 某些间隔会被跳过
- 多个定时器的代码执行之间的间隔可能会比预期的小
理解这幅图关键点在于:605ms处,第一个定时器代码仍在运行,同时队列中已经有了一个定时器代码实例,则605ms处被跳过。在600ms多一点处,直接运行405ms添加的代码
- 解决办法: 链式调用
setTimeout()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16setTimeout(function(){
//处理中
setTimeout(arguments.callee,intervel)
},intervel)
//使用例子
setTimeout(function(){
var div=document.getElementById("myDiv");
var left=parseInt(div.style.left)+5;
div.style.left=left+"px";
if(left<200){
setTimeout(arguments.callee,50);
}
},50)
2. Yielding Processes
JavaScript被严格限制了内存大小和处理器时间
其中一个限制是长时间运行脚本,即代码运行超过特定的时间或者特定语句数量就不让它继续执行。
两个原因:
- 过长的、过深嵌套的函数调用
- 进行大量处理的循环
某个循环占用时间长、不需要同步完成、不需要按顺序完成,则可实行数组分块。
基本思路: 为要处理的项目创建一个队列,然后使用定时器取出下一个要处理的项目进行处理,接着再设置另一个定时器。
1
2
3
4
5
6
7
8
9
10function chunk(array,process[,context]){
setTimeout(function(){
var item=array.shift();
process.call(context,item);
if(array.length>0){
setTimeout(arguments.callee,100);
}
},100);
}克隆数组方法:
array.concat()
;
3. 函数节流
- 函数节流:阻止某些操作高频率执行。
- 基本思路:某些代码不可以在没有间断的情况下连续重复执行。
1
2
3
4
5
6function throttle(method[,context]){
clearTimeout(method.tId);
method.tId=setTimeout(function(){
method.call(context);
},100);
}