Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

资源加载和页面渲染 #48

Open
coconilu opened this issue Aug 8, 2018 · 0 comments
Open

资源加载和页面渲染 #48

coconilu opened this issue Aug 8, 2018 · 0 comments

Comments

@coconilu
Copy link
Owner

coconilu commented Aug 8, 2018

概述

下面的描述有一个前提,就是你的网页结构是把CSS放在<head>标签里,<body>标签里没有JS代码需要执行,全部<script>都放在<body>标签后面。这是一个很好的约定俗成的规范。

1. 资源加载

当用户通过用户代理(浏览器)请求网站的时候,经过DNS解析、建立TCP连接,根据HTTP/HTTPS协议服务器会返回相关的资源给用户代理。其中的下载资源都是异步的,每个资源一个请求,比如HTML文件、CSS文件、JS文件、图片。当然了链接数是有上限的,这是用户代理的限制,比如同一时间只能下载资源上限为10个,那么第11个只能等到前面的资源下载完了才能进行。

2. 页面渲染

Talking is cheap. Let's see the piture below.

default

1. 构建RenderTree

根据 HTML 生成 DOM 树;根据 CSS 生成 CSSOM;将 DOM 和 CSSOM 整合形成渲染树(RenderTree)。

渲染树(RenderTree)只有构建好了,页面才能被渲染呈现。构建好的条件是解析完整个HTML文件,包括执行script脚本。

1. JS相关

嵌入JS脚本的方式有两种,一种是内联的方式(写在script标签里),一种是引入方式(使用src指定路径)。

所以思考JS的问题会从两个角度:

A. 加载JS

内联的方式是不用考虑网络问题的;如果是通过引入的方式加载JS,那么会等待JS下载好了才会执行。

但是有优化的地方:

script标签有async和defer属性的话:

  1. async指示浏览器是否在允许的情况下异步执行该脚本
  2. defer,设定用来通知浏览器该脚本将在文档完成解析后,触发 DOMContentLoaded 事件前执行
B. 执行JS

JS的执行会阻塞RenderTree的构建,所以会阻塞页面渲染,导致页面空白。

当遇到<script>标签时,会触发网页的渲染,因为JS有可能需要操作DOM和CSSOM,在执行JS的过程中会阻塞DOM的解析——也就会阻塞RenderTree的渲染和网页的呈现。

JS线程与GUI渲染线程是互斥的关系

2. 解析CSS

CSS所在的style标签本质上也是一个节点。

跟JS一样,可以从两个角度:

A. 加载CSS

一般而言,是通过同步加载的方式加载link标签里的css,整个过程会阻塞RenderTree的解析。

但是可以通过媒体查询的方式避免阻塞RenderTree的解析。比如:media="print"media="(min-width: 40em)"

B. 解析CSS

每当解析CSS的时候,会阻塞渲染RenderTree,但是不会阻塞DOM的解析。

CSS 是阻塞渲染的资源。需要将它尽早、尽快地下载到客户端,以便缩短首次渲染的时间。

所以一般会把样式放在head标签里。也可以通过 CSS“媒体类型”和“媒体查询”来解决这类用例。比如使用:

<link href="style.css" rel="stylesheet">
<link href="print.css" rel="stylesheet" media="print">
<link href="other.css" rel="stylesheet" media="(min-width: 40em)">
内容样式短暂失效(FOUC——Flash Of Unstyled Content)

场景:浏览器采用的是windows版本的IE浏览器,且版本在5.0以上(也就是现在所有的IE浏览器)。
解决方案:把样式link放在head里。

3. 小结

  1. JS语句的执行会阻塞DOM的解析和渲染,并让浏览器计算出当前的DOM(不完整,没有该script标签后面的标签)和CSSOM
  2. css加载不会阻塞DOM的解析,但是会阻塞RenderTree的渲染
  3. css加载会阻塞后面Script标签里的JS语句的执行

从浏览器优化性能角度去思考这个问题。

2. 布局(Layout)

结合浏览器的一些属性,计算RenderTree的几何信息,包括位置和大小等。

3. 绘制(Paint)

把RenderTree传给WebKit,由它调用相关的第三方库绘制到浏览器上展示。

4. 回流(reflow)和重绘(repaint)

用户和页面交互过程,如果发生页面DOM位置和大小变化则会触发回流(reflow);如果仅仅是样式的变化,比如背景颜色,那么仅会触发重绘(repaint)。

媒体查询由媒体类型以及零个或多个检查特定媒体特征状况的表达式组成。例如,上面的第一个样式表声明未提供任何媒体类型或查询,因此它适用于所有情况,也就是说,它始终会阻塞渲染。第二个样式表则不然,它只在打印内容时适用---或许您想重新安排布局、更改字体等等,因此在网页首次加载时,该样式表不需要阻塞渲染。最后,最后一个样式表声明提供由浏览器执行的“媒体查询”:符合条件时,浏览器将阻塞渲染,直至样式表下载并处理完毕。

参考

浏览器渲染页面过程与页面优化
深入剖析 WebKit
阻塞渲染的 CSS

@coconilu coconilu mentioned this issue Jun 23, 2020
68 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant