我是如何将首屏渲染降到1s左右的

693 阅读6分钟

简介

大家好,我是六六。经过这两天的学习和优化,终于把项目首屏渲染优化的可以了,为此来分享一下最近我学到的知识,如果有不好的地方大家多多指出来,喜欢的可以点一个赞哦。关注一下不迷路~

备注

1.cdn
2.gzip
3.异步路由
4.http缓存
5.图片懒加载
这些优化都基本知道,所以不多说。
在这些基础上再进行优化的。

目录

1.浏览器渲染机制
2.network面板参数详解
3.script标签与link标签
4.首屏渲染时机
5.如何优化
6.总结

1.浏览器渲染机制:

浏览器解析:
1、浏览器通过请求的 URL 进行域名解析,向服务器发起请求,接收文件(HTML、CSS、JS、Images等等)。
2HTML 文件加载后,开始构建 DOM Tree
3、CSS 样式文件加载后,开始解析和构建 CSS Rule Tree
4、Javascript 脚本文件加载后, 通过 DOM API 和 CSSOM API 来操作 DOM Tree 和 CSS Rule Tree

浏览器渲染:
1、浏览器引擎通过 DOM Tree 和 CSS Rule Tree 构建 Rendering Tree
2、Rendering Tree 并不与 DOM Tree 对应,比如像 标签内容或带有 display: none; 的元素节点并不包括在 
Rendering Tree 中 。
3、通过 CSS Rule Tree 匹配 DOM Tree 进行定位坐标和大小,是否换行,以及 positionoverflowz-index 
等等属性,这个过程称为 Flow 或 Layout 。
4、最终通过调用Native GUI 的 API 绘制网页画面的过程称为 Paint 。

我们知道了浏览器的工作原理后,接下来说说js,css,html这些资源是如何互相影响的:
1.我们知道样式表是不会影响dom的结构的,因此没有必要等待样式表并停止文档解析,但是js能操作dom和css啊,
所以遇到js标签dom停止解析,先去加载js了。
2.当script标签遇到defer和async时,会去单独开启一个线程去下载并不会阻塞html解析(后面重点说明)
3.解析到link标签的css时候,也会单独开启一个线程去下载资源,不影响html解析。
4.到遇到img标签时,也是异步加载图片资源,加载完成不会立马显示,因为css会影响图片的显示,所以说css会阻塞
图片的显示。

关于浏览器只是简单了解一下,只是对于我做优化的时候有用的地方,想要深入了解请看相关文章。

network面板参数说明:

先放两张图片吧:(都理解的话看下一部分)

第一张图:
queued:意思为请求排队的时间
started at:开始请求的时间
stalled:被挂起的时间,浏览器对同一个主机域名的并发连接数有限制,因此如果当前的连接数已经超过上限,那么其余
请求就会被阻塞,等待新的可用连接.
DNS Lookup:域名解析时间
initial connection:tcp建立三次握手的时间
request sent:第一个字节发出的时间到最后一个字节发后的时间,简称上传时间
Waiting(TTFB):请求发出后,到收到响应的第一个字节所花费的时间。
Content Download:下载时间。

第二张图:(重点)
requests:首屏渲染请求数量
transferred:文件大小
resources:资源文件大小
finish:所有请求响应完结束时间
load:页面加载完毕。DOM树构建完成后,继续加载html/css 中的图片资源等外部资源,加载完成后视为页面加载完毕。
DOMContentLoaded:DOM树构建完成。即HTML页面由上向下解析HTML结构到末尾封闭标签。

3.script标签和link标签

通过上面我们知道scirpt标签加载可以同步也可以异步,异步可以不用阻塞dom加载,有利于性能优化
defer:单独开一个线程来下载,下载完成等待dom构建完毕在执行多个defer标签按顺序执行
async:单独开一个线程来下载,但是下载完之后立即执行,这个时候会阻塞dom解析多个async谁先加载完执行谁

下面这张图更能理解:(借用网图)

link标签:
link标签加载css是异步操作(个人感觉是的)同时学到了一个新的属性
rel=prefetch:加上这个可以提前加载任何资源,不限于js,img等。提前的意思就是在浏览器空闲的时间提前缓存
这些资源。

4.首屏渲染是什么时候?

先理解一下首屏渲染的意思:是浏览器解析dom后首次绘制信息呈现给我们的时间,此ui能不能交互是未知的。

首屏渲染时间:这个时间节点发生在执行到第一个同步的script标签之中的。就是执行第一个js文件的某个时候浏览器首次渲染了。 下面我们开始来验证:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div class='main'></div>
    <style>
        div{
            text-align:center
        }
    </style>
    <script>
        const main=document.querySelector('.main')
        for(let i=0;i<100000;i++){
            let div=document.createElement('div')
            div.innerHTML='加油'
            main.appendChild(div)
        } 
        </script>
        <script>
             const div=document.querySelector('div')
             div.style.color='red'
        </script>
        <div style='position: fixed;top:0;right:100px;'>你好吗</div>
</body>

</html>

来解释一下:如果说我的结论是正确的,那么上端代码显示的顺序应该是如下:

  • 执行第一个script标签,显示加油居中的文字(此时第二个scirpt标签还没执行到,所以颜色没改变)
  • 执行第二个script标签,将文字变成红色
  • 解析div标签,显示你好吗

下面为揭秘时刻:(大家也可以自己去演练)

5.如何优化首屏渲染速度的:

学习了以上的知识,我们应该对于首屏优化更加得心应手了吧,我的项目是这么优化的:
1.我是前端判断客户端的类型pc或者移动,然后进行跳转,写了一个script标签,通过webpack打包后再body上面,
因为head标签打包了很多引入资源,所以在跳转之前有很多无意义的请求。然后js文件就阻塞了渲染,最后我直接在head
标签第一行写入这个标签了。
2.一些ui框架我用cdn引入,在进行network查看的时候发现了响应时间太长了,所幸就把资源下载下来,放到服务器
和oss上面去引入,发现小文件在oss响应速度很快,大文件则在服务器上面响应很快。远远快过cdn.
3.首页不需要的script标签直接异步加载就好(defer)

6.总结

具体怎么优化最后还是看需求,到底是首页显示时间还是首页可交互时间,优化的核心思路还是没有变的。
大家有什么问题也可以和我交流交流。有什么不对的地方大家多多指出,对于优化这一块我也是小白~