在浏览器中,Javascript执行与UI更新是发生在同一个进程(浏览器UI线程)中的。UI线程的工作基于一个简单的队列系统,任务会被保存到队列中直到进程空闲时被提取出来执行。所以Javascript的执行会阻塞UI更新;反之,UI更新也会阻塞Javascript的执行。给用户的表现就是浏览器在工作时短暂或长时间失去反应,用户的操作不能及时得到响应。而UI线程的阻塞很多时候是由于我们要在代码里进行长时间的脚本运算,超过了浏览器限制,导致浏览器失去响应,冻结用户界面。
所以,编码时对于耗时较长的运算我们不得不考虑UI线程的问题
3、长时间运行脚本限制
1 var fibonacci = (function() { 2 var cache = [1, 1]; 3 var fib = function(n) { 4 if (n > 1) { 5 for (var i = cache.length; i <= n; i++) { 6 cache[i] = cache[i - 1] + cache[i - 2]; 7 } 8 } 9 return cache[n - 1]; 10 }; 11 return fib; 12 })();
还是上面使用Memoization技术实现的fibonacci函数,执行fibonacci(10000000),由于运算时间长,触发了浏览器长时间运行脚本限制,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)要快。