从一道面试题说起—你知道哪些前端性能优化方法

被裁员之后,在家休息了一周,现在开始苦兮兮的面试日子。面了几家,发现这个问题出现的频率过于高了,这里通过另一道面试题,浏览器输入URL后发生了什么为思路,做一个简单的反思总结。

浏览器输入URL并按下回车

无优化点

浏览器查找当前URL是否存在缓存

有一次面试,面试官问了个问题,你知道浏览器有哪些缓存方法。我当时第一反应是localstorage那一套东西,突突突报了一遍。面试官笑笑说,你这才说了一半,然后我人就傻了。回来后查了一些资料,原来想说的是这个东西。学习了一下相关的知识,这里记录一下。

强缓存(不走服务器)

强制缓存流程

在没有缓存数据的时候,浏览器向服务器请求数据时,服务器会将数据和缓存规则一并返回,缓存规则信息包含在响应header中。对于强制缓存来说,响应header中会有两个字段来标明失效规则(Expires/Cache-Control)
Expires值为服务器返回的到期时间,HTTP1.0标准,现已废弃
Cache-Control 有更详细的缓存规则

协商缓存(走服务器)

对比缓存流程

浏览器第一次请求数据时,服务器会将缓存标识与数据一起返回给客户端,客户端将二者备份至缓存数据库中。
再次请求数据时,客户端将备份的缓存标识发送给服务器,服务器根据缓存标识进行判断,判断成功后,返回304状态码,通知客户端比较成功,可以使用缓存数据。

Last-Modified 服务器在响应请求时,告诉浏览器资源的最后修改时间。
If-Modified-Since 再次请求服务器时,通过此字段通知服务器上次请求时,服务器返回的资源最后修改时间。

Etag  /  If-None-Match(优先级高于Last-Modified  /  If-Modified-Since)
Etag 服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定)。
If-None-Match 再次请求服务器时,通过此字段通知服务器客户段缓存数据的唯一标识。

总结

对于强制缓存,服务器通知浏览器一个缓存时间,在缓存时间内,下次请求,直接用缓存,不在时间内,执行比较缓存策略。
对于比较缓存,将缓存信息中的Etag和Last-Modified通过请求发送给服务器,由服务器校验,返回304状态码时,浏览器直接使用缓存。

优化点

服务器对静态资源设置浏览器缓存信息,浏览器在有缓存的情况下直接从本地读取资源。

DNS域名解析

当浏览器访问一个域名的时候,需要解析一次DNS,获得对应域名的ip地址。在解析过程中,按照浏览器缓存系统缓存路由器缓存ISP(运营商)DNS缓存根域名服务器顶级域名服务器主域名服务器的顺序,逐步读取缓存,直到拿到IP地址
DNS Prefetch,即DNS预解析就是根据浏览器定义的规则,提前解析之后可能会用到的域名,使解析结果缓存到系统缓存中,缩短DNS解析时间,来提高网站的访问速度

<link rel="dns-prefetch" href="https://www.google.com">
<link rel="dns-prefetch" href="https://www.google-analytics.com">

CDN

使用cdn分发,将用户的请求重新导向距离较近的服务节点。其目的是使用户可就近取得所需内容,解决 Internet网络拥挤的状况,提高用户访问网站的响应速度

TCP连接

DNS解析后得到了服务器的ip,接下来就是和服务器建立起连接,这通过TCP的三次握手完成。

浏览器向服务器发送HTTP请求

减少请求次数,为什么要减少请求次数,
合并外部请求的js、css文件
运用CSS精灵合并处理多个icon文件、运用图标字体、把小图标转为base64

浏览器接收响应体

对请求的文件进行打包(webpack),减少文件体积,使用gzip压缩

页面渲染

浏览器构建的步骤,大概如下:
1、处理HTML标记并构建DOM树
2、处理CSS标记并构建CSSOM树
3、将DOM与CSSOM合并成一个渲染树
4、根据渲染树来布局,以计算每个节点的集合信息
5、将各个节点绘制到屏幕

js的影响

js是会阻塞页面渲染,所以把js放在body底部,或者异步

css的影响

前端页面渲染时会根据DOM结构生成一个DOM树,然后加上CSS样式生成渲染树。如果CSS文件放在标签中,则CSS Rule Tree会先于DOM树完成构建,之后浏览器就可以边构建DOM树边完成渲染;反之,CSS文件放在所有页面标签之后,比如之前,那么当DOM树构建完成了,渲染树才构建,浏览器不得不再重新渲染整个页面,这样造成了资源的浪费。而且页面还可能会出现闪跳的感觉,或者白屏或者布局混乱或者样式很丑,直到CSS加载完成,页面重绘才能恢复正常。
因此,一般来讲,css标签应放在标签之间。但如果css文件较大,会让首页白屏时间更长,所以并不是说把css都放顶部是一个完美的方法。权衡利弊,应该把必须的css(js)放顶部,把不那么重要的css(js)放底部。

千辛万苦,终于做出来了!

自从会写html开始就一直想搞一个自己的博客,开始碍于能力有限,一直没找到头绪。时隔一年,终于做好了,记录一下小踩的坑。

后台搭建

命令行弱鸡果断选择现成的面板工具。使用宝塔进行全局的运维管理,方便快捷, 各种环境一键搭建。这真不是广告,实在是太友好了。

现有的环境选择nginx+mysql,以后打算增加node的管理接口,先摆个坑在这。ftp、phpmyadmin这些都是宝塔一键安装,当个添头,操作起来也很方便。node进程现在用pm2管理,回头还要补下文档,暂时只跑了一个wakatime-async,可以把wakatiame的数据存到gist上,定时任务每天凌晨一点半抓一下,通过server酱推送到微信。

其他应用全跑docker上,体感上宿主机各种进程管理会比较清晰。

Docker踩坑

基于之前已经操作过docker,对其命令还是略有了解,这里记录一下奇奇怪怪的坑。

博客先选用了wordpress,docker一键搭建。后台苦手,自己搭一套文章管理怕不是再过两年,先跑起来再说。

因为宿主机上的宝塔已经建了sql服务,这里选择wordpressdocker连接宿主机sql服务。于是就有了第一个大坑,容器跑起来

docker run -d --name wordpress -e WORDPRESS_DB_HOST=localhost:3306 -p 1080:80 wordpress

进1080端口,咦,发现连不上服务器。

原来这里WORDPRESS_DB_HOSTlocalhost就会到容器自己的localhost,连不到宿主机上。这里搜了些资料,宿主机ifconfig命令找到docker的虚拟网卡ip,填上,还是连不上服务器??这里就是第二个大坑了,左思右想,寻思可能是数据库权限的问题,因为新装的数据库不允许外部访问,于是

 update user set host=‘%’ where user=‘root’

好了,这回进1080端口,一切正常了。

nginx

再然后,现在还需要加端口号,我想直接输入域名就可以访问我的小破站。配了一下nginx

server 
{
    listen 80;
    server_name luv.plus;
    index index.html index.htm index.php default.html default.htm default.php;
    location /
    {
        proxy_pass   http://127.0.0.1:1080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-PORT $remote_port;
        proxy_set_header X-Real-IP $remote_addr; 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

中间有一个坑是没有加set_header的部分,一进网站就跳127.0.0.1。没弄明白怎么回事,回头再补nginx的相关知识吧。