浏览器渲染机制

首先介绍一些基本概念

一、浏览器的主要组成

1. user interFace 用户界面

地址栏、书签、前进/后退/主页等,不同浏览器不一样

2. browser engine 浏览器引擎

用来查询及操作渲染引擎的接口

3. rendering engine 渲染引擎

解析html(Parse HTML)、解析样式(Parse Stylesheet) 、发送请求(send Request)、解析javascript(Evaluate Javascript)、重新计算样式(Recalculate Style)、计算布局样式(Layout)、更新Layer Tree(Update Layer Tree)、绘制(Paint) 、混合layers(Composite Layers)等

4. network 网络

用来发送请求(send Request)

5. javascript interpreter

解析javascript(Evaluate Javascript), 由编译和执行阶段组成

6. UI-backend ui后端

绘制(Paint)节点

7. data persistence 数据存储

文件缓存: 离线缓存manifiest、http缓存
数据缓存:localstorage、sessionstorage、cookie、indexDB

二、在浏览器地址栏输入一个url, 到渲染出一个页面, 发生了什么?

浏览器中输入url,发生了什么.jpeg

下面用一个例子详细描述上面的过程, 前往

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>浏览器的渲染机制</title>
    <link rel="stylesheet" href="./css/main.css">
    <link href="https://cdn.bootcss.com/element-ui/2.4.0/theme-chalk/index.css" rel="stylesheet">
    <script src="./js/main.js"></script>
    <script src="./js/async.js" async></script>
    <script src="./js/defer.js" defer></script>
    <script>
        window.addEventListener('pageshow', function () {
            console.log('pageshow')
        })
        window.addEventListener('load', function () {
            console.log('load')
        })
    </script>
</head>

<body>
    <div>lalala</div>
    <ul></ul>
    <script>
        var $ul = document.querySelector('ul')
        var result = ''
        for (let i = 0; i < 10; i++) {
            result += '<li>列表项' + i + '</li>';
        }

        $ul.innerHTML = result
    </script>
    <div>北京欢迎你</div>
</body>
</html>
  1. 解析html
    浏览器解析html是从上往下执行的,渲染引擎 负责Parse HTML 、Parse Stylesheet、Recalculate Style、Layout、Update Layer Tree、Receive Response、Receive Data,network 负责 Send request, javascript interpreter负责Evaluate Javascript。下面分析 每一行代码,浏览器是如何处理的
# Parse HTML开始
# 定义文档类型, 告诉浏览器以什么标准解析html
<!DOCTYPE html>
<html lang="en">
# 发送请求, Parse HTML继续
<link rel="stylesheet" href="./css/main.css">
# 发送请求, Parse HTML继续
<link href="https://cdn.bootcss.com/element-ui/2.4.0/theme-chalk/index.css" rel="stylesheet">
# 发送请求, Parse HTML继续
<script src="./js/main.js"></script>
# 发送请求, Parse HTML继续
<script src="./js/async.js" async></script>
# 发送请求, Parse HTML继续
<script src="./js/defer.js" defer></script>

# Parse HTML停止, 等待请求完成

然后会等待上面的资源加载完成, 并按照顺序执行。async和defer是异步加载,defer在DOMContentLoaded之前按顺序执行, async加载完即执行。async和普通script的区别是async资源的加载不会阻塞Parse HTML.执行顺序如下

Parse Stylesheet(main.css) -->Parse Stylesheet(index.css)-->Evaluate Javascript(main.js)
async.js加载完就会执行, 没有顺序。
defer .js会在解析完</html>标签之后, 触发DOMContentLoaded事件之前按顺序执行。执行完所有的defer script, 然后重新计算样式 (recalcuate style)构建render tree, 然后触发DOMContentLoaded事件。

发送请求.jpeg

执行.jpeg

从上面两幅图中可以看到, main.css加载完后, 马上就执行了Parse Stylesheet; 而main.js 加载完后, 会等待index.css 加载完并执行完Parse Stylesheet, 才会执行Evaluate Javascript. 因为这里css、js执行顺序和定义的顺序需要保持一致。

# Parse HTML 开始
// script标签会阻塞Parse HTML, 执行完script里面的内容之后, 才会继续往下解析
<script>
    window.addEventListener('pageshow', function () {
        console.log('pageshow')
    })
    window.addEventListener('load', function () {
        console.log('load')
    })
</script>
# Parse HTML 继续
<body>
    <div>lalala</div>
    <ul></ul>
# Parse HTML继续
// script标签会阻塞Parse HTML, 执行完script里面的内容之后, 才会继续往下解析
<script>
    var $ul = document.querySelector('ul')
    var result = ''
    for (let i = 0; i < 10; i++) {
        result += '<li>列表项' + i + '</li>';
    }
    $ul.innerHTML = result
</script>
# Parse HTML继续
    <div>北京欢迎你</div>
</body>
# Parse HTML, DOM tree 构建完成
</html>
  1. Evaluate defer script, 执行异步defer脚本

  2. 触发DOMContentLoaded事件

  3. recalculate style, 构建render tree

  4. Layout、Update Layer tree

  5. paint、composite Layers


    rendering.jpeg

三、prefetch、preload、dns-prefetch

# DNS预解析
<link rel="dns-prefetch" href="//cdn.bootcss.com">
# 浏览器会在空闲时间加载prefetch中的内容, 存储在磁盘上, 不会执行里面的js; 
<link rel="prefetch" href="main.js">

# 如果prefetch已完成, 会从缓存中读取; 如果未完成,会再次发起请求。所以prefetch可能会造成资源的重复请求.
<script src="./js/main.js"></script>
# 浏览器会立即加载preload中的内容, 保持在内存中, 不会执行里面的js.
<link rel="preload" href="/main.js" as="script">

# 如果preload已经完成, 会从内存缓存中读取;如果不存在, 会等待preload完成。
<script src="./js/main.js"></script>

所以prefetch一般用于预加载下个页面即将用到的资源,preload用于提前加载当前页面用到的资源。

优先级: preload > 普通 > prefetch

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,547评论 4 374
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,787评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,175评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,752评论 0 223
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,169评论 3 297
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,056评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,195评论 2 321
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,980评论 0 214
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,724评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,872评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,344评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,667评论 3 264
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,379评论 3 245
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,202评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,992评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,189评论 2 286
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,987评论 2 279

推荐阅读更多精彩内容