DNS 解析也是须要时间的,能够经过预解析的方式来预先得到域名所对应的 IP。javascript
<link rel="dns-prefetch" href="//yuchengkai.cn">
复制代码
缓存对于前端性能优化来讲是个很重要的点,良好的缓存策略能够下降资源的重复加载提升网页的总体加载速度。html
一般浏览器缓存策略分为两种:强缓存和协商缓存。前端
实现强缓存能够经过两种响应头实现:Expires
和 Cache-Control
。强缓存表示在缓存期间不须要请求,state code
为 200java
Expires: Wed, 22 Oct 2018 08:41:00 GMT
复制代码
Expires
是 HTTP / 1.0 的产物,表示资源会在 Wed, 22 Oct 2018 08:41:00 GMT
后过时,须要再次请求。而且 Expires
受限于本地时间,若是修改了本地时间,可能会形成缓存失效。面试
Cache-control: max-age=30
复制代码
Cache-Control
出现于 HTTP / 1.1,优先级高于 Expires
。该属性表示资源会在 30 秒后过时,须要再次请求。算法
若是缓存过时了,咱们就可使用协商缓存来解决问题。协商缓存须要请求,若是缓存有效会返回 304。跨域
协商缓存须要客户端和服务端共同实现,和强缓存同样,也有两种实现方式。浏览器
Last-Modified
表示本地文件最后修改日期,If-Modified-Since
会将 Last-Modified
的值发送给服务器,询问服务器在该日期后资源是否有更新,有更新的话就会将新的资源发送回来。缓存
可是若是在本地打开缓存文件,就会形成 Last-Modified
被修改,因此在 HTTP / 1.1 出现了 ETag
。性能优化
ETag
相似于文件指纹,If-None-Match
会将当前 ETag
发送给服务器,询问该资源 ETag
是否变更,有变更的话就将新的资源发送回来。而且 ETag
优先级比 Last-Modified
高。
对于大部分的场景均可以使用强缓存配合协商缓存解决,可是在一些特殊的地方可能须要选择特殊的缓存策略
Cache-control: no-store
,表示该资源不须要缓存Cache-Control: no-cache
并配合 ETag
使用,表示该资源已被缓存,可是每次都会发送请求询问资源是否更新。Cache-Control: max-age=31536000
并配合策略缓存使用,而后对文件进行指纹处理,一旦文件名变更就会马上下载新的文件。由于浏览器会有并发请求限制,在 HTTP / 1.1 时代,每一个请求都须要创建和断开,消耗了好几个 RTT 时间,而且因为 TCP 慢启动的缘由,加载体积大的文件会须要更多的时间。
在 HTTP / 2.0 中引入了多路复用,可以让多个请求使用同一个 TCP 连接,极大的加快了网页的加载速度。而且还支持 Header 压缩,进一步的减小了请求的数据大小。
更详细的内容你能够查看 该小节
在开发中,可能会遇到这样的状况。有些资源不须要立刻用到,可是但愿尽早获取,这时候就可使用预加载。
预加载实际上是声明式的 fetch
,强制浏览器请求资源,而且不会阻塞 onload
事件,可使用如下代码开启预加载
<link rel="preload" href="http://example.com">
复制代码
预加载能够必定程度上下降首屏的加载时间,由于能够将一些不影响首屏但重要的文件延后加载,惟一缺点就是兼容性很差。
能够经过预渲染将下载的文件预先在后台渲染,可使用如下代码开启预渲染
<link rel="prerender" href="http://example.com">
复制代码
预渲染虽然能够提升页面的加载速度,可是要确保该页面百分百会被用户在以后打开,不然就白白浪费资源去渲染
对于代码层面的优化,你能够查阅浏览器系列中的 相关内容。
懒执行就是将某些逻辑延迟到使用时再计算。该技术能够用于首屏优化,对于某些耗时逻辑并不须要在首屏就使用的,就可使用懒执行。懒执行须要唤醒,通常能够经过定时器或者事件的调用来唤醒。
懒加载就是将不关键的资源延后加载。
懒加载的原理就是只加载自定义区域(一般是可视区域,但也能够是即将进入可视区域)内须要加载的东西。对于图片来讲,先设置图片标签的 src
属性为一张占位图,将真实的图片资源放入一个自定义属性中,当进入自定义区域时,就将自定义属性替换为 src
属性,这样图片就会去下载资源,实现了图片懒加载。
懒加载不只能够用于图片,也可使用在别的资源上。好比进入可视区域才开始播放视频等等。
对于一张 100 * 100 像素的图片来讲,图像上有 10000 个像素点,若是每一个像素的值是 RGBA 存储的话,那么也就是说每一个像素有 4 个通道,每一个通道 1 个字节(8 位 = 1个字节),因此该图片大小大概为 39KB(10000 * 1 * 4 / 1024)。
可是在实际项目中,一张图片可能并不须要使用那么多颜色去显示,咱们能够经过减小每一个像素的调色板来相应缩小图片的大小。
了解了如何计算图片大小的知识,那么对于如何优化图片,想必你们已经有 2 个思路了:
head
中script
标签放在 body
底部,由于 JS 文件执行会阻塞渲染。固然也能够把 script
标签放在任意位置而后加上 defer
,表示该文件会并行下载,可是会放到 HTML 解析完成后顺序执行。对于没有任何依赖的 JS 文件能够加上 async
,表示加载和渲染后续文档元素的过程将和 JS 文件的加载与执行并行无序进行。Webworker
。Webworker
可让咱们另开一个线程执行脚本而不影响渲染。静态资源尽可能使用 CDN 加载,因为浏览器对于单个域名有并发请求上限,能够考虑使用多个 CDN 域名。对于 CDN 加载静态资源须要注意 CDN 域名要与主站不一样,不然每次请求都会带上主站的 Cookie。
对于代码运行错误,一般的办法是使用 window.onerror
拦截报错。该方法能拦截到大部分的详细报错信息,可是也有例外
Script error.
对于这种状况咱们须要给 script
标签添加 crossorigin
属性arguments.callee.caller
来作栈递归对于异步代码来讲,可使用 catch
的方式捕获错误。好比 Promise
能够直接使用 catch
函数,async await
可使用 try catch
可是要注意线上运行的代码都是压缩过的,须要在打包时生成 sourceMap 文件便于 debug。
对于捕获的错误须要上传给服务器,一般能够经过 img
标签的 src
发起一个请求。
如何渲染几万条数据并不卡住界面
这道题考察了如何在不卡住页面的状况下渲染数据,也就是说不能一次性将几万条都渲染出来,而应该一次渲染部分 DOM,那么就能够经过 requestAnimationFrame
来每 16 ms 刷新一次。
<!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>Document</title>
</head>
<body>
<ul>控件</ul>
<script> setTimeout(() => { // 插入十万条数据 const total = 100000 // 一次插入 20 条,若是以为性能很差就减小 const once = 20 // 渲染数据总共须要几回 const loopCount = total / once let countOfRender = 0 let ul = document.querySelector("ul"); function add() { // 优化性能,插入不会形成回流 const fragment = document.createDocumentFragment(); for (let i = 0; i < once; i++) { const li = document.createElement("li"); li.innerText = Math.floor(Math.random() * total); fragment.appendChild(li); } ul.appendChild(fragment); countOfRender += 1; loop(); } function loop() { if (countOfRender < loopCount) { window.requestAnimationFrame(add); } } loop(); }, 0); </script>
</body>
</html>
复制代码