大多数浏览器让一个单线程共用于执行javascript和更新用户界面。每个时刻只能执行其中的一种操作。
1.浏览器UI线程
共用于执行javascript和更新用户界面的进程通常被称为“浏览器线程”
1.1浏览器限制
浏览器限制了javascript任务的执行时间。确保某些恶意代码不能通过永不停止的密集操作锁住用户的浏览器或计算机。限制分为:调用栈大小限制和长时间运行脚本限制。
当达到了此限制时,浏览器会显示一个对话框:例如IE会提示用户是否停止执行当前脚本。
IE默认设置了 500万条语句,firefox默认10秒,safari默认5秒,chrome通过自带的崩溃系统处理。
1.2 单个脚本的javascript的操作时间不能超过100ms。
2.使用定时器让出时间片段
2.1有些javascript任务不能再100ms或者更短的时间内完成。这个时候最理想的方法就是让出UI线程的控制权,使UI可以更新,然后再执行javascript。
创建一个定时器会造成UI线程暂停,如同从一个任务切换到下一个任务。溢出定时器会重置所有相关的浏览器限制,包括长时间运行脚本定时器。此外,调用栈也在定时器代码中重置为0。
2.2 定时器的精度
javascript的定时器延迟通常不太精准,相差大约几毫秒,定时器不可用于测量实际时间。定时器的最小值建议为25毫秒。
2.3使用定时器处理数组
长时间运行脚本的起因一种就是耗时过长的循环。
典型的简单循环模式
for(var =0,len=items.length;i<len;i=++){
process(items[i]);
}
这类循环结构运行时间过长的原因主要是process()的复杂度或items的大小,或两者兼有。
使用定时器取代循环的两个决定性因素:
(1)处理过程是否必须同步
(2)数据是否必须按顺序处理
如果两个都是否,那么就适用定时器分割任务。
基本模式:
var todo=items.concat();
setTimeout(function(){
process(todo.shift());
if(todo.length>0){
setTimeout(arguments.callee,25);
}else{
callback(items);
}
},25);
批处理模式:
function processArray(items, process ,callback ){
var todo=items.concat();
setTimeout(function(){
var start=+new Date();
do{
process(todo.shift());
} while(todo.length>0&&(+new Date() - start <50));
if(todo.length>0){
setTimeout(arguments.callee,25);
}else{
callback(items);
}
},25);
}