JSFiddle - React, Tailwind, and code Playground
by camnpr
HTML
由于运算时间长,触发了浏览器长时间运行脚本限制,UI线程被阻塞了。所以,迭代中有大规模运算,100ms内完成不了的任务可以进行拆分,让javascript短暂让出UI线程控制权,以执行其他任务。
要短暂让出UI线程控制权,可以使用setTimeout。
setTimeout的时间精度:
javascript中定时器是有时间精度的, IE9(非充电模式)、IE8及其以下版本的时间精度是15.6ms;IE9(充电模式)下是4ms;其他浏览器一般也是4ms,低于4ms会降低电池使用寿命。所以,setTimeout(fn, 0)并非马上执行的,其执行时机取决于时间精度。
为了解决setTimeout在不同浏览器的时间精度问题,W3C因此引入了新的setImmediate()函数。setImmediate与setTimeout类似,setImmediate会在UI线程空闲时将任务插入到队列并执行,我们不再需要关心时间精度的影响。并且,setImmediate执行起来比setTimeout(fn, 0)要快。
由于任务运行时间的不确定性,在迭代运算中,可以加上运算时间监控,决定此次迭代是否需要拆分任务。
我们来做一个简单的demo,0~n的累加运算:
JavaScript
// o~n的累加运算
var test = function(n, callback) {
var result = 0;
var i = 0;
(function() {
var st = +new Date();
for (; i < n; i++) {
if ((+new Date()) - st < 100) {
result++;
} else {
setTimeout(arguments.callee, 0); // 运算时间差大于100ms时,中断运算,让出UI线程控制权
return;
}
}
callback && callback();
})();
};
alert(test(10000000, showResult)); // 1千万次累加
//由于额外的流程控制开销,setTimeout方式相对直接运算会消耗更多的时间,好处是UI线程不再阻塞,可以处理更多的任务。
//除了setTimeout方式,将需要长时间运算的操作放到flash里面进行也是一种解决方案,避开javascript单一线程的影响。