写在前端性能优化以前你应该知道的 - 浏览器的加载和渲染

  前言
javascript

    一直想写点关于前端性能的东西,后来感受所谓的性能优化最基本的前提是你要知道浏览器是如何针对web页面工做的.后来因为过年以及换工做等缘由耽搁下来,只好利用这个休息的周末写一下.     前端

    原本打算好好研究一下关于前端性能优化的一些内容,看了一些发现有的地方不是很明了.因此以为先把浏览器加载渲染这个过程摸清楚,本文是多方总结和我本身的一点研究,若是有不对的地方,还请指出,谢谢. java

 
web

    首先咱们要有一个概念,浏览器显示出一个页面,即便只拿前端抛开服务器和数据库,也是一个很复杂的过程.尽管它很复杂,但仍是有一的步骤和流程的,了解这些步骤你才会清除的知道哪里耗费了过多的资源,从而进行人为的优化.
shell

    在一个页面上咱们一般会看到种内容,HTML-CSS-Javascript.在一个文件中它们会经过各类方式引入,而后会被浏览器分别解析.当咱们经过一个URL地址进入页面时,工做就开始了.首先浏览器将HTML解析为一个DOM-Tree,而后将CSS规则解析为一个CSS-Tree,最后则是Javascript的下载和执行.
数据库


    在这个过程当中,浏览器是按照必定顺序进行的,其中的任何一个步骤出现问题均可能致使页面没法显示.
浏览器

  解析 性能优化

    当完成了上面的解析过程后,浏览器引擎会根据这些解析的结果构建出Rendering-Tree,它会生成的规则将CSS样式应用到对应的element上,而且计算每一个element的位置,这就是Reflow的过程.
服务器

    在这一过程当中,DOM-Tree 的生成相对容易,比较耗费性能的是CSS匹配HTML这一过程,因此对着CSS解析不少地方都有提出:DOM的结构要尽可能简单,要小,不要过分嵌套,CSS尽可能用class和id.
app

  渲染

    在没说以前我就要先告诉你们,渲染是一个很消耗性能的过程.这就意味着若是你要优化你的前端性能,能够在这一部分针对每个动做进行检查和优化.

    黄色部位就是渲染过程的几个动做,先进行样式的计算,而后够将Rendering-Tree,而后定位坐标以及大小等各类样式属性,最后画出来.上面有些线没有连贯是由于Javascript修改了DOM或者CSS致使必须从新Layout,又或者CSS规则没有匹配到.

    若是你早先对前端性能有概念,那么Repaint和Reflow这两个词你必定不会陌生.  

    Repaint - 表示页面上一部分的内容要从新画,多是颜色什么的,可是元素的大小和位置不须要改变,也就是不影响其相邻的内容.

    Reflow - 表示页面上一部份内容的大小或者位置变化了,这会引发周围元素的连锁反应,致使整个Rendering-Tree重构.

    经过描述咱们能够看到Reflow的动做成本要比Repaint高得多,因此在平时的工做中咱们要尽可能避免浏览器的Reflow.对于CSS浏览器是能够并行下载的,可是要注意这其中可能会发生的Reflow.

  JS的加载和执行

    Javascript在整个浏览器渲染的进程中始终是个不安份的因素,更多的时候它充当着规则的破坏者这种角色.由于它能够操做DOM的特性,使得以前生成好的DOM-Tree颇有可能发生改变.

    浏览器对于Javascript奉行了两个原则,首先加载即执行,其次在其执行的期间阻塞其余内容(包括DOM的解析和其余资源的下载等).这是由于没法肯定Javascript的执行会给DOM-Tree或者CSS带来怎样的变化,因此在JS执行的状况下,整个浏览器处于单核状态.看到这你就不难理解为何不少地方都推荐将CSS写在页面最前面,而将Javascript写在页面最后的缘由了.

    IE从6开始支持一个defer属性,它加在<script>标签中,做用是使Javascript脚本并行下载,而且等到都下载完在顺序执行,但仅支持IE.

    HTML5也不甘示弱,加入了相似的async属性,不过它坚决遵照Javascript加载后当即执行的原则,因此存在弊端,容易使有顺序的JS代码失控,而且不是全部版本的浏览器都支持,因此不常使用.

  标准解决方案-动态DOM

    为了解决Javascript脚本载入的问题,人们又找出经过建立script节点的方式.

function loadjs(script_filename) {
    var script = document.createElement('script');
    script.setAttribute('type', 'text/javascript');
    script.setAttribute('src', script_filename);
    script.setAttribute('id', 'coolshell_script_id');
 
    script_id = document.getElementById('coolshell_script_id');
    if(script_id){
        document.getElementsByTagName('head')[0].removeChild(script_id);
    }
    document.getElementsByTagName('head')[0].appendChild(script);
}
 
var script = 'a.js';
loadjs(script);
    看一下代码,传递一个url参数,而后用建立element的方式建立一个script节点.这一过程就将脚本载入而且执行了.固然其实还有一种Ajax的方式,不过原理差很少,有兴趣的能够自行百度.

  结尾

    其实浏览器整个的处理比这写的要复杂的多,上面的过程只是简化了.了解整个浏览器的渲染进程那么咱们对什么影响了网页的加载?这个问题应该有了一点认识,比较重要的一个Repaint和Reflow,另外一个就是JS操做DOM.

    一些建议:

  •     若是能提早定义好一个class去赋值给DOM,就别一个个DOM节点的遍历而后逐个添加style了,在楼下大喊一句远比挨个单元去敲门省力.
  •     建立的DOM结构尽量简洁,层次少,另外不要再DOM节点中运算.
  •     table这种布局省事是省事,不过典型的牵一发而动全身,改一个地方其余都要变,因此尽可能不要用.
  •     JS的性能浪费的不是在代码自己的执行,而是对DOM和CSS的操做.

    受能力所限,写的可能有不对的地方还请谅解,欢迎你们留言讨论.

相关文章
相关标签/搜索