Javascript:再论Javascript的单线程机制 之 DOM渲染时机
背景
Javascript是单线程事件驱动的,所有能看到的Javascript代码都是在一个线程执行,定时器回调和AJAX回调会在适当的时刻插入队列等待Javascript线程调度执行,今天想测试一下DOM渲染的线程与时机,具体的问题是:
修改DOM会立即显示在UI中吗?
一个小测试
测试代码
1 <!DOCTYPE html> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 5 <title></title> 6 <script src="Scripts/jquery-2.0.3.js"></script> 7 </head> 8 <body> 9 <p>DOM的修改不会立马导致渲染,而是会内部触发一个事件(可能叫paint),这个事件的处理程序会被插入到Javascript的调度队列中等待调度执行。</p> 10 <div id="Test1" style="height: 100px; margin: 5px; background-color: yellow;"></div> 11 </body> 12 </html> 13 <script type="text/javascript"> 14 15 function sleep(millisecond) { 16 var start = new Date().getTime(); 17 18 do { 19 var end = new Date().getTime(); 20 } while (end - start <= millisecond); 21 } 22 23 setTimeout(function () { 24 console.log('start...'); 25 26 $("#Test1").css({ 27 backgroundColor: 'red' 28 }); 29 30 sleep(3000); 31 32 console.log('...end'); 33 }, 2000); 34 35 </script>
测试结果
DOM的修改不会立马导致渲染,而是会内部触发一个事件(可能叫paint),这个事件的处理程序会被插入到Javascript的调度队列中等待调度执行。
一个小例子
需求
在DOM中显示1至20的斐波那契数组。
实现
1 <!DOCTYPE html> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 5 <title></title> 6 <script src="Scripts/jquery-2.0.3.js"></script> 7 </head> 8 <body> 9 <div id="Test2" style="height: 100px; margin: 5px; background-color: blue;"></div> 10 </body> 11 </html> 12 13 <script type="text/javascript"> 14 setTimeout(function () { 15 var fibonacci = function (n, callback) { 16 if (n == 1 | n == 0) { 17 callback(n); 18 } 19 20 setTimeout(function () { 21 fibonacci(n - 1, function (n_1) { 22 fibonacci(n - 2, function (n_2) { 23 callback(n_1 + n_2); 24 }); 25 }); 26 }, 0); 27 } 28 29 for (var i = 1; i <= 20; i++) { 30 fibonacci(i, function (result) { 31 $("#Test2").append(result + '<br/>'); 32 }); 33 } 34 }, 4000); 35 </script>
分析
如果采用传统的递归方式,界面至少卡死N分钟,以这种形式递归,保证界面不至于卡死。
备注
时刻铭记:单线程+事件驱动。