ThinkSSL🔒 一键申购 5分钟快速签发 30天无理由退款 购买更放心 广告
## js引擎与GUI引擎是互斥的 [setTimeout 的黑魔法 - 李三思 - 博客园](http://www.cnblogs.com/fly-snow/p/5427865.html) > js引擎与GUI引擎是互斥的 怎么证明,浏览器的js线程和GUI渲染线程是互斥的呢?很简单: ```html var main = document.getElementById('main'); var newNode = document.createElement("div"); newNode.className = 'book'; main.appendChild(newNode); while(true){} ``` js主线程死循环,一直被占用,所以GUI线程没机会运行,所以页面看不到节点插入。 **深入试验** ```html var arr = [1,2,3,4,5,6]; for (var i in arr) { alert(i); console.log('i:', i); var newNode = document.createElement("div"); newNode.className = 'book'; main.appendChild(newNode); } // 这样是实现不了那种效果的,你看到的alert(弹出来一个,你点下确定,插入一个)只是一种错觉假象,你看alert并没有阻塞控制台,说明其实不管你点不点,alert并没有阻塞js主进程,它只是阻塞了渲染进程而已。 // 抱歉上面是猜想,不对,下面试验过了才对 // 可以实现那种效果(点一下,插入一个DOM,控制台输出一下),控制台被阻塞了,alert会阻塞js的主进程,但是很奇怪,既然阻塞了js的主线程,即js进程没有结束,那么GUI进程此时应该互斥啊,怎么会出现插入效果呢,应该是阻塞完控制台,完后最后才渲染啊,所以这个alert有点特殊,不是你想的那种阻塞,你把alert放在循环外就知道了,它其实并没有阻塞js主进程,点下插入和控制台的效果都是假象。 参见:[JS学习笔记(一)——JS的阻塞特性 - MeteorSeed - 博客园](http://www.cnblogs.com/MeteorSeed/articles/2283629.html) ---------- var arr = [1,2,3,4,5,6]; for (var i in arr) { setTimeout(function () { console.log('i:', i); var newNode = document.createElement("div"); newNode.className = 'book'; main.appendChild(newNode); }, 1000); } 这样也是实现不了那种效果的,这样js主线程可以在瞬间执行完,插入动作都被定时器堆积到事件队列了,最终约1秒后也是瞬间循环完事件队列,所以也是看到一下子全部插入的。 --------- 改进版 var arr = [1,2,3,4,5,6]; for (var i in arr) { setTimeout(function () { console.log('i:', i); var newNode = document.createElement("div"); newNode.className = 'book'; main.appendChild(newNode); }, 1000 * i); } 这样可以实现那种效果,因为这样就不会发生事件堆积了,中间隔开了一秒。 ``` 所以我们平常实现运算出一个结果就插入一个节点(一般是消息应用,那种效果能增强体验感,而不是一下子插入那么生硬,让人感觉实体是一个个插入的),那种节点一个一个插入实际上是假效果,运算在js主线程中很快就会完成,运算完成后才会轮到js渲染线程插入节点,所以我们看到的效果就是所有节点一下子几乎同时插入显示的就是因为这个原因。 lazyFade库可以模拟那种效果。 所以正真做到,在循环中,循环一个插入一个是不可能的,不可能实时的,因为 js引擎与GUI引擎互斥 所以实际情况并不是我们想的那样的,不过这样没什么,这是因为浏览器决定的,确实想要那种视觉效果,可以使用lazyFade或者上面说的方法实现。(注意没有,这里我开始说视觉效果了,而不是真实效果了,因为我们已经知道真实效果在浏览器中不存在,我们只能面对现实,接收显示,模拟出视觉效果,自己骗自己,穷开心而已) ### 参考 - [JS学习笔记(一)——JS的阻塞特性 - MeteorSeed - 博客园](http://www.cnblogs.com/MeteorSeed/articles/2283629.html) - [关于javascript你要知道的](https://www.kancloud.cn/xiak/quanduan/369159) - [你真的了解script标签吗?](https://www.kancloud.cn/xiak/quanduan/278616) - [浏览器的 16ms 渲染帧](http://www.tuicool.com/articles/iyI7Rve) - [window.requestAnimationFrame - Web API 接口 | MDN](https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestAnimationFrame) - [JavaScript 运行机制详解:再谈Event Loop - 阮一峰的网络日志](http://www.ruanyifeng.com/blog/2014/10/event-loop.html) - [Javascript高性能动画与页面渲染](http://www.infoq.com/cn/articles/javascript-high-performance-animation-and-page-rendering/) ```html 看看下面这样一段代码: function jank(second) { var start = +new Date(); while (start + second * 1000 > (+new Date())) {} } div.style.backgroundColor = "red"; // some long run task jank(5); div.style.backgroundColor = "blue"; 无论在任何的浏览器中运行上面的代码,你都不会看到div变为红色,页面通常会在假死5秒,然后容器变为蓝色。这是因为浏览器的始终只有一个线程在运行(可以这么理解,因为js引擎与UI引擎互斥)。虽然你告诉浏览器此时div背景颜色应该为红色,但是它此时还在执行脚本,无法调用UI线程。 ``` - [16毫秒的优化——Web前端性能优化的微观分析 - MBA智库文档](http://doc.mbalib.com/view/31010c7871f2c899e48d6d782543cf88.html) - [使用requestAnimationFrame实现js动画性能好_javascript技巧_脚本之家](http://www.jb51.net/article/70678.htm) - [CSS3动画那么强,requestAnimationFrame还有毛线用? « 张鑫旭-鑫空间-鑫生活](http://www.zhangxinxu.com/wordpress/2013/09/css3-animation-requestanimationframe-tween-动画算法/) ### 扩展 test.html ```html <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta http-equiv="Content-Language" content="zh-cn"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <meta name="keywords" content="keywords"> <meta name="description" content="description"> <link href="favicon.ico" rel="icon" type="image/x-icon"> <link href="" type="text/css" rel="stylesheet"> <script src=""></script> <title>Document</title> <style> .book { width: 200px; height: 50px; background: red; margin-top: 10px; } </style> </head> <body> <div id="main"></div> <script> var o = true; var main = document.getElementById('main'); (function() { var i = 0; var i2 = 0; // setTimeout(function () { // i++; // console.log('i:', i); // var newNode = document.createElement("div"); // newNode.className = 'book'; // main.appendChild(newNode); // setTimeout(function () { // i++; // console.log('i:', i); // var newNode = document.createElement("div"); // newNode.className = 'book'; // main.appendChild(newNode); // }, 1000); // }, 1000); // var newNode = document.createElement("div"); // newNode.className = 'book'; // main.appendChild(newNode); // while(true){} // while (o && i2 < 10) { // setTimeout(function () { // i2++; // console.log('i2:', i2); // var newNode = document.createElement("div"); // newNode.className = 'book'; // main.appendChild(newNode); // }, 1000); // } }()); </script> </body> </html> ``` last update:2017-9-2 12:18:02