- js代码需要JavaScript引擎转换成汇编代码。再从汇编语言转化成0101二进制的机器语言才能被计算机识别。并且上面步骤转成机器语言后都是由CPU来执行的。所以CPU对代码的运行有很大的关键
JS引擎和内核的区别
内核包含了两部分:
- WebCore:(也就是渲染引擎)用于解析HTML和渲染
- JavaScriptCore:和V8引擎一样,也就是JS引擎的一种。负责解析和执行JS代码
- 浏览器渲染的过程:
HTML解析成DOM树。CSS解析成CSSOM成为Attachment(附加)。CSSOM和DOM形成Render渲染树。此时还需生成另外一个layout布局计算每个元素的位置大小等。这样就可以对渲染树进行绘制Painting。然后展示在页面上
一般来说,渲染引擎根据JavaScript提供的桥接接口提供给JavaScript访问DOM的能力,很多HTML5也是通过桥接接口实现的。
桥接接口复杂而不高效往往是一个性能瓶颈,所以才说DOM的频繁使用会导致性能问题。
渲染阻塞
Ø CSS阻塞
- 什么是CSS阻塞?
由于CSSOM负责存储渲染信息,浏览器就必须保证在合成渲染树之前,CSSOM是完备的,这种完备是指所有的CSS(内联、内部和外部)都已经下载完,并解析完,只有CSSOM和DOM的解析完全结束,浏览器才会进入下一步的渲染,这就是CSS阻塞渲染。
- 明确是在哪里阻塞的?
(1) css会阻塞dom解析吗?不会的,因为css不会影响到dom树的形成。
(2) css会阻塞js执行吗?会的,它会阻塞在它后面的js脚本的执行。
(3) css会阻塞dom渲染吗?会的,如果css加载不阻塞DOM树渲染的话,那么当css加载完之后,DOM树可能又得重新重绘或者回流了。
- 怎么优化?
(1) 样式放在head中,为了更早的解析CSS,保证更快的首次渲染。加
(1)preload 属性提高加载优先级。
(2) Gulp合并压缩,减少请求大小和个数,提高加载速度。
(3) 使用合理的css选择器。
- 怎么选择合理的css选择器?
(1) CSS选择器的读取顺序是从右向左。
例子分析:#molly div.haha span{color:#f00}
浏览器会按照从右向左的顺序去读取选择器。先找到span然后顺着往上找到class为“haha”的div再找到id为“molly”的元素。成功匹配到则加入结果集,如果直到根元素html都没有匹配,则不再遍历这条路径,从下一个span开始重复这个过程。
(2) 练习分析:
n A. div.box { color: #f00;}; div#box { color: #f00; };
nB. .box { color:#f00;} #box { color: #f00; };
(B 优点在于类选择器,id选择器已经能比较准确的帮我们匹配对应的元素,无需再比对一层。)
n A.div>a{}; B.div a{}
(A优点在于A使用子选择器,当找到a标签的元素后只需比对a的上一层是否div便可确定,而B使用后代选择器,需要遍历父级,再遍历父级的父级,直到遍历完成。)
(3) 总结选择规律
² 避免id选择器或者类选择器和标签选择器配合使用。
² 尽量缩短匹配路径的长度。
² 尽可能不使用通配符选择器。
² 减少后代选择器的使用。
² 尽可能使用继承。
- for循环用let和var的区别
如下:
此时结果输出3个3.这是因为我们如果用var的话,最后会共用一个i。也就是for循环结束后的i。
如果我们把var换成let的话。因为let会产生多个块级作用域,所以此时函数的i是相互独立的。如果说,在使用let的情况下产生了块级作用域,每次循环的i都是独立的一份,并不共用,那有个问题,第二次循环 i++ 自增时又是怎么知道上一个块级作用域中的 i 是多少的。这里得到的解释是从阮一峰ES6入门获取的。
JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。
- GC浅理解
源地址:https://www.cnblogs.com/echolun/p/11503915.html
怕被删所以摘抄一部分:
.垃圾回收的两种模式:
- 引用计数
引用计数
引用计数的判断原理很简单,就是看一份数据是否还有指向它的引用,如果没有任何对象再指向它,那么垃圾回收器就会回收,举个例子:
// 创建一个对象,由变量o指向这个对象的两个属性
var o = {
name: '听风是风',
handsome: true
};
// name虽然设置为了null,但o依旧有name属性的引用
o.name = null;
var s = o;
// 我们修改并释放了o对于对象的引用,但变量s依旧存在引用
o = null;
// 变量s也不再引用,对象很快会被垃圾回收器释放
s = null;
引用计数存在一个很大的问题,就是对象间的循环引用,比如如下代码中,对象o1与o2相互引用,即便函数执行完毕,垃圾回收器通过引用计数也无法释放它们。
function f() {
var o1 = {};
var o2 = {};
o1.a = o2; // o1 引用 o2
o2.a = o1; // o2 引用 o1
return;
};
f();
- 标记清除
标记清除的概念也好理解,从根部出发看是否能达到某个对象,如果能达到则认定这个对象还被需要,如果无法达到,则释放它,这个过程大致分为三步:
a.垃圾回收器创建roots列表,roots通常是代码中保留引用的全局变量,在js中,我们一般认定全局对象window作为root,也就是所谓的根部。
b.从根部出发检查所有 的roots,所有的children也会被递归检查,能从root到达的都会被标记为active。
c.未被标记为active的数据被认定为不再需要,垃圾回收器开始释放它们。
下面有个GIF图很明了。在上面地址中。。。
当一个对象零引用时,我们从根部一定无法到达;但反过来,从根部无法到达的不一定是严格意义上的零引用,比如循环引用,也就是上面的例子。两个对象循环引用,但是此时是达不到根元素的,所以也被视为要清除回收的资源。所以标记清除要更优于引用计数。
从2012年起,所有现代浏览器都使用了标记清除垃圾回收算法,但老版本的IE6除外。