页面性能优化:前端缓存最佳实战

励志文章 阅读(1048)
亚洲通

  08:15:35昊明有态度

  前言

缓存,这是一个常见的主题,通常用作前端访谈的知识点。

本文重点介绍如何在实际项目中设置缓存并提供更合理的解决方案。

强缓存和协商缓存

在引入缓存时,我们习惯将缓存划分为强缓存和协商缓存。两者之间的主要区别在于是否在使用本地缓存时向服务器验证本地缓存是否仍然有效。顾名思义,协商缓存意味着与服务器协商以确定是否使用本地缓存。

两个缓存方案的问题

强缓存

我们知道强大的缓存主要由http请求标头中的Cache-Control和Expire字段控制。 Expire是HTTP 1.0标准下的一个字段,我们可以在这里忽略它。我们专注于Cache-Control字段。

通常,我们将Cache-Control的值设置为“public,max-age=xxx”,这意味着在xxx秒内再次访问资源,并使用本地缓存,并且不向服务器发出请求。

显然,如果服务器上的资源在xxx秒内更新,客户端将看到旧内容而不强制刷新。如果你不赶时间,你可以接受这个,它是完美的吗?然而,很多时候它并不像你想象的那么简单。如果在发布新版本时后台界面也会更新,那么gg。缓存的用户仍在使用旧界面,该界面已被后台杀死。怎么做?

谈判缓存

协商缓存的最大问题是每次必须验证缓存对服务器的有效性时,似乎很容易,无论多少,你都要问我是否有效。然而,对于有追求的代码农民来说,这是不可接受的。每次去服务器,缓存有什么意义?

最佳实践

缓存的含义是减少请求,使用更多本地资源,为用户提供更好的体验,并降低服务器压力。所以,最好的做法。它应该尽可能地高速缓存,同时,在更新版本时,客户端的缓存可能会失效。

更新版本后,如何让用户尽快使用最新的资源文件?机智的前端提出了一种在更新版本时改变静态资源路径的方法。这相当于第一次访问这些资源,不会出现缓存问题。

Webpack允许我们在打包时为文件名带来哈希值。

条目: {main: path.join(__ dirname,''),vendor: ['react','antd']},输出: {path: path.join(__ dirname,''),publicPath:'/dist /' ,filname:'bundle。[chunkhash] .js'}

总之,我们可以提出更合理的缓存方案:

HTML:使用协商缓存。 CSS&JS&Picture:使用强缓存,文件名和哈希值。

哈希也很特别

从对等方接收数据时失败

方法1:使用文件大小和修改时间

Functionstattag(STAT){。varmtime=stat.mtime.getTime()的toString(16)varsize=stat.size.toString(16)返回 '' '' +大小+ ' - ' + +修改时间 '' ''}

方法2:使用文件内容的哈希值和内容长度

Functionentitytag(实体){如果(entity.length===0){//快速pathemptyreturn '' '0-2jmj7l5rSw0yVb/vlWAYkK/YBwk' ''} //computehashofentityvarhash=crypto.createHash( 'SHA1')。更新(实体,'utf8')。digest('base64')。substring(0,27)//computelengthofentityvarlen=typeofentity==='string'?Buffer.byteLength(entity,'utf8'): entity.lengthreturn'''' + len.toString(16)+ ' - ' +散列+ '' ''}

谁是ETag和Last-Modified?

协商缓存,有两个字段ETag和Last-Modified。当这两个字段同时存在时,哪个字段优先?

在Express中,新包用于确定它是否是最新资源。主要源代码如下:

Functionfresh(reqHeaders,resHeaders){//fieldsvarmodifiedSince=reqHeaders [ '如果改性-因为'] varnoneMatch=reqHeaders [ '如果 - 无匹配'] //unconditionalrequestif(!modifiedSince &&!noneMatch){returnfalse} //AlwaysreturnstalewhenCache-控制: no-cache //tosupportend-to-endreloadrequests //varcacheControl=reqHeaders ['cache-control'] if(cacheControl && CACHE_CONTROL_NO_CACHE_REGEXP.test(cacheControl)){returnfalse} //if-none-matchif(noneMatch && noneMatch!=='*' ){varetag=resHeaders ['etag'] if(!etag){returnfalse} varetagStale=truevarmatches=parseTokenList(noneMatch)for(vari=0; i