• 浏览器渲染


    搞清楚浏览器渲染的过程对于前端优化是很有用处的!最近看了一些博客和文章稍微做些总结,具体细节进一步参照原文链接和相关文章!

    最终决定浏览器表现出来的页面效果的差异是:渲染引擎 Rendering Engine(也叫做排版引擎),也就是我们通常所说的“浏览器内核”(IE--Trident,FF--Gecko,Opera--Presto,Chrome--Webkit),负责解析网页语法(如HTML、JavaScript)并渲染、展示网页。相同的代码在不同的浏览器呈现出来的效果不一样,那么就很有可能是不同的浏览器内核导致的。

    对于页面加载一种最简单的描述形式是:

    1、用户访问网页,发送一个http请求到网络服务器。
    2、网络服务器(应用服务器)解析请求,发送请求给数据库服务器。
    3、数据服务器返回数据给网络服务器,网络服务器解析数据,并生成html文件内容放入http response中,返回给浏览器。
    4、浏览器解析http response。
    5、浏览器创建DOM树。
    6、浏览器下载css,并应用在DOM树上,进行渲染。
    7、浏览器下载js,并解析执行js。
     
    后面三步可以用下图进一步说明:

    1、解析HTML以重建DOM树(Parsing HTML to construct the DOM tree ):渲染引擎开始解析HTML文档,转换树中的标签到DOM节点,它被称为“内容树”

    2、构建渲染树(Render tree construction):解析CSS(包括外部CSS文件和样式元素),根据CSS选择器计算出节点的样式,创建另一个树 —- 渲染树

    3、布局渲染树(Layout of the render tree): 从根节点递归调用,计算每一个元素的大小、位置等,给每个节点所应该出现在屏幕上的精确坐标。

    4、绘制渲染树(Painting the render tree) : 遍历渲染树,每个节点将使用UI后端层来绘制。

    主要的流程就是:构建一个dom树,页面要显示的各元素都会创建到这个dom树当中,每当一个新元素加入到这个dom树当中,浏览器便会通过css引擎查遍css样式表,找到符合该元素的样式规则应用到这个元素上。

     
    在上面的流程中,只要有一个环节出现问题,渲染页面都不能正常进行。比如说:
    服务器端:
    网络服务器:无法获取到资源文件(404),或者由于并发的原因暂时无法处理你的请求(最常见的500错误),你的浏览器会长时间处于空白状态,直到服务器返回状态,或者进行超时处理。
    数据层:如果服务器停止,或忙于处理大数据等等,长时间无法返回数据给网络服务器,那么网络服务器一直处于等待状态中,如果请求量达到最大值,那么后面的请求都被堵塞,从而无法及时返回内容给浏览器。
     
    客户端:
    JavaScript:如果你的js写在body里,而且这个js执行非常复杂的逻辑,那么整个页面处于等待状态中。
    不论js代码是内联还是包含在一个不相干的外部文件中,页面下载和解析过程肯定会停下,等待脚本执行完成这些处理,然后才能继续进行。
    大多数浏览器使用单进程处理JavaScript的多个任务,同一时间只能有一个任务执行。
     
    CSS:
    PS:浏览器可以同时下载多个CSS文件。
    如果我们把CSS样式放在页面底部,虽然使页面内容能更快的加载(因为将加载css 文件的时间放在最后,从而使页面内容先显示出来),但这样的内容是没有样式的,在CSS文件加载进来后,浏览器再对DOM使用样式,会出现我们常说的“无样式之闪烁”。
    更讨厌的是,上下都放置CSS样式,浏览器会首先按照上面的进行渲染,等到下面的样式上来,再按照下面的样式进行回流(reflow)和重绘(repaint),用户感觉很差。
     
    注意两个词“repaint"和"reflow":(具体可以参照http://news.cnblogs.com/n/178402/后半部分更详细介绍)
    repaint(重绘):在一个元素的外观被改变,但没有改变布局的情况下发生。——如果只是改变某个元素的背景色、文字颜色、边框颜色等等不影响它周围或内部布局的属性,将只会引起浏览器repaint。
    reflow(回流):浏览器发现某个部分发生了点变化影响了布局,需要倒回去重新渲染,这个回退的过程就叫回流。
     
    改进方案:
    服务端:
    从语言层面考虑,我们可以使用逐步返回内容的方式,输送数据给浏览器,如我们可以使用php的flush,把整个head部分,半个body加一部分div返回给浏览器,进行渲染,然后把其他部分逐步输送到浏览器。
    我们可以在服务端使用多线程或多进程的方式并发去进行数据处理。

    JavaScript:

    1、把脚本进行压缩(移除不必要的字符,注释以及空行)。

    2、对部分js文件进行合并,以减少http的请求个数,以减少服务器端的压力——但是要量力而行,因为如果你的js文件很大,下载很慢的话,很多功能都不能正常进   行,我们可以按照业务进行合并。

    3、使用外部js文件。因为现在很多浏览器都有缓存,明显会减少http请求数。

    4、将脚本放在页面底部。先让用户看到内容,然后再加载js,这样用户会感觉页面加载速度很快。

    CSS:

    1、合并多个css文件,以减少http的请求个数,以减少服务器端的压力。

    2、使用外部css文件。主要原因是浏览器缓存,以减少http请求。

    3、放在页面顶部(head标签处),防止出现“无样式内容的闪烁”。

    PS:

    <quote>

    http://www.smallni.com/css-performance-from-the-browsers-rendering/

    css引擎查找样式表,对每条规则都按从右到左的顺序去匹配。 看如下规则:

    #nav li{}

    看起来很快,实际上很慢,尽管这让人有点费解。我们中的大多数人,尤其是那些从左到右阅读的人,可能猜想浏览器也是执行从左到右匹配规则的,因此会推测这条规则的开销并不高。在脑海中,我们想象浏览器会像这样工作:找到唯一的ID为nav的元素,然后把这个样式应用到直系子元素的li元素上。我们知道有一个ID为nav的元素,并且它只有几个li子元素,所以这个CSS选择符应该相当高效。

    在CSS书写过程中,总结出有如下性能提升的方案:

    1. 避免使用通配规则,如 *{} 计算次数惊人!只对需要用到的元素进行选择;
    2. 尽量少的去对标签进行选择,而是用class,如:#nav li{},可以为li加上nav_item的类名,如下选择.nav_item{};
    3. 不要去用标签限定ID或者类选择符,如:ul#nav,应该简化为#nav;
    4. 尽量少的去使用后代选择器,降低选择器的权重值。后代选择器的开销是最高的,尽量将选择器的深度降到最低,最高不要超过三层,更多的使用类来关联每一个标签元素;
    5. 考虑继承,了解哪些属性是可以通过继承而来的,然后避免对这些属性重复指定规则。

    可以看一下CSS selectors Test,这个实验的重点是评估复杂选择符和简单选择符的开销。

    但说到底,CSS性能这东西对于小的项目来讲可能真的是微乎其微的东西,提升可能也不是很明显,但对于大型的项目肯定是有帮助的。而且一个好的CSS书写习惯和方式能够帮助我们更加严谨的要求自己。(赞成作者这个说法!)

    </quote>

    推荐阅读:
     
  • 相关阅读:
    进程与线程
    前端教程大全
    vuex的五大属性和使用方法
    vue中以this.$xx的属性详解
    VUE-element-admin项目地址
    从零开始学 Web 之 Vue.js(三)Vue实例的生命周期
    从零开始学 Web 之 Vue.js(四)Vue的Ajax请求和跨域
    vue使用promise.all异步实现多个请求完成之后在执行某些操作
    react受控组件与非受控组件
    react生命周期
  • 原文地址:https://www.cnblogs.com/ttcc/p/3817407.html
Copyright © 2020-2023  润新知