我们都知道运行在桌面的应用往往能够随意控制他们需要的内存大小和处理器时间,但是运行在浏览器中的JavaScript都被分配了一个确定数量的资源,JavaScript被严格限制了,以防止恶意的web程序员把用户的计算机搞挂了。其中一个限制是长时间运行脚本的制约,如果代码运行超过特定的时间或者特定语句数量就不让它继续执行。如果代码达到了这个限制就会弹出一个浏览器错误的对话框,告诉用户某个脚本会用过长的时间执行,询问是否继续执行还是停止它。定时器是绕开此限制的方法之一。
脚本执行的时间过长由两个原因之一造成:(1)过长的、过深嵌套的函数调用;(2)进行大量处理的循环,后者所占原因居多。由于JavaScript的执行是一个阻塞操作,脚本运行所花的时间越久,用户无法与页面交互的时间也越久。考虑使用数组分块思想,数组分块可以将多个项目的处理在执行队列上分开,在每个项目处理之后,给予其他的浏览器处理机会运行,这样就可能避免长时间运行脚本的错误。根据经验,一旦某个函数需要花50ms以上的时间完成,那么最好是考虑将任务分割为一系列可以使用定时器的小任务。
当发现某个循环占用了大量时间,业务层对数据的处理要求不需要同步完成且处理数据顺序不是很重要,就可以考虑使用定时器分割这个循环。这个技术就叫数组分块,小块小块的处理数组,通常每次一小块。基本的思路是:为要处理的项目建一个队列,然后使用定时器取出下一个要处理的项目进行处理,接着在设定另一个定时器,依次类推。
function chunk(array,process,context){setTimeout(funcion(){//取出下一个条目并处理var item=array.shift();process.call(context,item);//若还有条目,再设置另一个定时器if(array.length>0){setTimeout(arguments.callee,100);}},100);}
在数组分块模式中,这个array变量包含了要处理的项目。chunk()方法接受三个参数:要处理的项目的数组,用于处理项目的函数,可选的运行函数的作用域。定时器的时间设置为100ms,使得JavaScript进程有时间在处理项目的事件之间转入空闲。
根据业务层 实际需要,有时候实际使用中可能会需要保存要来的数组。则可以这样处理:传递给chunk的数组是用作一个队列的,因此当处理数据的同时,数组中的条目也在变化,如果想保持原数组不变,则应该将数组的克隆传递给chunk()。
chunk(array.concat(),process,context){}
当不传递任何参数调用某个数组的concat()方法时,将返回和原来数组中项目一样的数组。这样就可以保证原数组不会被该函数更改。