[笔记] 浏览器渲染

这些文章的笔记:

http://imweb.io/topic/56841c864c44bcc56092e3fa

https://zhuanlan.zhihu.com/p/29418126

##Repaint and Reflow - 重绘和回流

重绘(repaint):屏幕的一部分重画;

回流(reflow/layout):需要重新计算渲染树(render tree),可能会重新绘制整个屏幕;

回流的原因:HTML使用流式布局(flow based layout),如果某元件的几何尺寸发生了变化,就需要重新布局,也就是回流。

回流的过程:从这个root frame开始递归往下,依次计算所有节点的几何尺寸和位置,也有可能增加新的frame。

预防回流应当避免的操作

  1. 增加、删除、修改DOM节点;
  2. 移动DOM的位置,或者是动画;
  3. 修改css样式;
  4. resize窗口(移动端没有这个问题),或者是滚动;
  5. 修改网页的默认字体;
  6. display:none会触发reflow,而visibility:hidden只会触发repaint,因为没有发现位置变化。

总结reflow的几个原因

  • 网页初始化(initial);
  • js操作dom(incremental);
  • 元件尺寸变化(resize);
  • css属性变化(styleChange);
  • 几个incremental菜单reflow发生在同一个frame的子树上面(dirty);

异步reflow/增量异步reflow:积攒reflow或repaint的操作一次性完成。
但是如果resize窗口或者改变了默认页面的字体会立即回流。

一些建议

  • 预先定义好css的class,然后修改dom的classname;
  • dom离线后修改
    • 使用documentFragment对象在内存里操作dom;
    • 先把dom给display:none,然后修改,改完再显示;
    • clone一个dom节点到内存里,改完后和在线的交换;
  • 不要把dom节点的属性值放在一个循环里面当成循环的变量,会导致大量地读写这个节点的属性;
  • 尽可能修改层级比较低的dom;
  • 为动画的HTML元件使用fixed或者absolute的position;
  • 不要使用table布局,table的一个小改动会造成整个table的重新布局;

阻塞渲染

浏览器总是并行加载资源
(当HTML解析器被脚本阻塞的时候,解析器虽然会停止构建dom,但是仍然会识别该脚本后面的资源)

  • css被视为阻塞渲染的资源,也就是说浏览器在CSSOM构建完毕之前不会渲染任何已处理的内容,也不会执行js脚本;
  • js不仅可以读取和修改dom属性,还可以读取和修改CSSOM属性;
  • 当浏览器遇到一个script标记时,dom构建将暂停,直至脚本完成执行;

建议

  1. css优先,引入顺序上css资源先于js资源;
  2. js应该尽量少影响dom的构建;

对于css

浏览器会优先处理link标签引入的资源,因此

  • 精简css并尽快提供它;
  • 用媒体类型(media type)和媒体查询(media query)来解除对渲染的阻塞。

对于js

script标签会阻塞HTML解析,无论是不是内联script。

改变阻塞模式

async和defer属性对于内联的脚本都是无效的;

1. defer

延迟执行引入的js(这段js加载时HTML并未停止解析,过程并行);

整个document解析完毕且defer的脚本也加载完成之后(顺序不定),在执行defer脚本的js代码,然后触发DOMContentLoaded事件;

特点:

  • 载入js文件时不阻塞HTML的解析;
  • 执行阶段被放到HTML标签解析完成之后。

2. async

异步执行引入的js(如果已经加载好,就会开始执行,无论此刻是HTML解析阶段还是DOMContentLoaded触发之后);

这种方式下加载的js依然会阻塞load事件,async脚本可能在DOMContentLoaded触发之前或之后执行,但是一定在load触发之前执行;

多个async脚本的执行顺序是不确定的

向document动态添加script标签时,async属性默认是true

向document动态添加link标签时,是否阻塞渲染是根据浏览器的不同而表现不同的

另外,不建议采用document.write和innerHTML来添加script和link标签。

你可能感兴趣的:(js,浏览器)