长时间运行的javascript任务
对于浏览器来说,一些复杂的javascript不能在100毫秒或更短时间内完成。这时候,UI线程被长时间占用,页面UI得不到更新,对于用户来说是非常不好的体验。
这时候最理想的方法就是让出UI线程的控制权,让出控制权意味着停止执行javascript,使得UI有机会更新。然后再执行javascript。
创建一个 定时器 会造成UI线程暂停。
使用定时器处理数组
一种常见的造成长时间运行脚本的起因是耗时过长的循环。
典型的简单循环模式:
for (var i = 0 , len = items.length; i < len; i++) {
process(items[i]);
}
是否可以用定时器取代循环的两个决定性因素:
- 处理过程不需要同步
数据是不需要按顺序处理
一种基本的异步代码模式: var todo = items.concat(); //克隆数组 setTimeout(function(){ // 取得数组的下一个元素并出栈。 process(tods.shift()); // 如果还有需要处理的元素,创建另一个定时器 if(todo.length > 0){ setTimeout(argument.callee , 25) // argument.callee 匿名函数下调用本身。 }else{ callback(items); // 没有需要处理的元素了,执行回调函数。 } },25)
函数封装:
/*
*处理耗时过长的异步循环。
*参数:待处理数组,处理数组的函数,回调函数
*/
function processArray(items,process,callback){
var todo = items.concat(); //克隆数组
setTimeout(function(){
// 取得数组的下一个元素并出栈。
process(tods.shift());
// 如果还有需要处理的元素,创建另一个定时器
if(todo.length > 0){
setTimeout(argument.callee , 25)
// argument.callee 匿名函数下调用本身。
}else{
callback(items);
}
},25)
}
分割任务
多任务函数导致长时间运行
function saveDocument(id){
// 写入文档
openDocument(id);
writeText(id);
closeDocument(id);
// 更新UI
updata(id);
}
处理思路:将每个任务函数放在一个数组中,然后使用前面提到的数组处理模式。
function saveDocument(id){
var tasks = [openDocument,writeText,closeDocument,updataUI];
setTimeout(function(){
// 执行下一个任务
var task = tasks.shift();
task(id);
// 检查是否还有任务
if(task.length > 0){
setTimeout(argument.callee , 25)
}
},25);
}
函数封装:
/*
*分割多任务函数的长时间运行javascript
*参数:任务步骤数组,参数,回调函数
*/
function multistep(steps,args,callback){
var tasks = steps.concat();
setTimeout(function(){
// 执行下一个任务
var task = tasks.shift();
task.apply(null,args || []);
// 检查是否还有任务
if(task.length > 0){
setTimeout(argument.callee , 25)
}else{
callback();
}
},25);
}
定时器与性能
- 定时器可以让你的javascript整体代码性能带来优化,但过度使用也会造成负面影响。本篇博客代码使用的了定时器序列,同一时间只有一个定时器存在,只有当这个定时器结束时才会新创建一个。
- 当多个重复的定时器同时创建往往会出现性能问题,因为只有一个UI线程,而所有的定时器都在争夺运行时间。在使用定时器优化性能时,注意避免这种情况。