有意请求:pi时代的缓存策略

曾几何时,我们依赖浏览器来处理缓存;在那些日子里,作为开发者,我们几乎没有控制权。但随后进步的网络应用(的PWA)服务人员,缓存API- 和突然,我们有超过什么放入缓存被它如何被放在那里广阔的力量。现在,我们可以缓存的一切,我们要...,这其中就有一个潜在的问题。

继续下面的条

媒体文件,尤其是图像,弥补整体平均页重量的这些天,它变得更糟。为了提高性能,人们倾向于尽可能多地缓存这些内容,但我们应该这样做吗?在大多数情况下,不会。即使所有这些新奇的技术在我们的指尖,伟大的表现仍然取决于一个简单的规则:只请求你所需要的,并使每个请求尽可能小

为我们的用户提供最好的体验而不滥用他们的网络连接或硬盘,是时候对一些经典的自旋的最佳实践,与媒体缓存策略实验,尝试一些缓存API技巧,服务人员隐藏他们的袖子。

最好的意图# section2

我们从优化拨号上网网页中学到的所有经验教训,在移动电话开始流行时又变得非常有用,并且在今天我们为全球用户所做的工作中继续适用。不可靠或高延迟的网络连接在世界上许多地方仍然是常态,这提醒我们,假设一个技术基线平均地或与它相应的前沿同步地提升是不安全的。这就是性能最佳实践:历史证明,现在对性能有利的方法在未来将继续对性能有利。

在服务工人出现之前,我们可以提供对浏览器的一些指令它们应该缓存特定资源的时间,但仅此而已。下载到用户机器上的文档和资产将被放到用户硬盘上的一个目录中。当浏览器为某个特定的文档或资产组装请求时,它会首先查看缓存,看看是否已经有了可能避免触及网络所需的内容。

如今,我们对网络请求和缓存有了相当多的控制,但这并不能成为我们不考虑web页面上的资源的借口。

只要求你需要什么#SECTION3

正如我所说,今天的网络是糟糕的与媒体。图片和视频已经成为通信的主要方式。他们很可能转换,当涉及到销售和营销,但他们几乎没有高性能的,当涉及到下载和渲染速度。考虑到这一点,每一个图像(和视频等)应具有针对其在网页上的位置而战。

几年前,报纸上刊登了一篇关于用烈酒(酒精,不是鬼魂)做菜的文章,其中就包括我的一份食谱。我没有订阅那份报纸的印刷版,所以当文章发表时,我去了那个网站看看结果如何。在最近的一次重新设计中,该网站决定将所有文章加载到一个几乎全屏的模态视图框中,该视图框位于其主页的顶部。betway体育注册这意味着请求文章需要请求与文章页面关联的所有资产所有的内容和资产的主页。哦,和网页有视频广告,复数。而且,是的,他们的自动播放。

我打开DevTools,发现页面的重量已经超过了15mb。蒂姆·卡德莱克(Tim Kadlec)最近刚刚推出什么我的网站的成本?,所以我决定检查一下损坏情况。结果表明,对于美国普通用户来说,浏览该页面的实际成本要高于当天报纸的印刷版。真是一团糟。

当然,我能责怪谁建的网站做他们的读者这样的伤害的人们,但现实情况是,我们没有去工作,我们的恶化用户体验的目标。这可能发生在我们身上的。我们可以花几天审议页面的性能只有有一些委员会决定组精心制作的网页上面自动播放视频广告的时代广场。想象一下更糟糕的事情是,如果我们被堆叠在彼此的顶部的两个深不可测,进行网页!

当竞争激烈的时候(比如在报纸的首页),媒体可以很好地吸引注意力,但是当你想让读者专注于一项任务(比如阅读实际的文章),它的价值就会从重要下降到“很好的拥有”。“是的,研究表明图片很擅长吸引眼球,但是一旦访问者进入文章页面,没人在乎;我们要做的仅仅是它需要更长的时间来下载和更昂贵的访问。这种情况只能越来越糟,因为我们推更多的媒体到页面中。

我们必须尽我们的力量来减少我们的网页的重量做的一切,所以要避免的事情上不增加价值的请求。对于初学者来说,如果你正在写关于数据泄露的文章,抵制的冲动,包括那张可笑的照片在一个非常黑暗的房间里连帽衫打字一些随机花花公子的计算机上。

请求最小的文件#section4

现在,我们已经采取了我们的股票需要包括,我们必须问自己一个关键的问题:我们怎样才能实现它以最快的方式可能吗?这可能是一样简单选择最合适的图像格式对于所呈现的内容(并对其进行优化),或者像完全重新创建资产那样复杂(例如,从光栅图像切换到矢量图像是否更有效)。

提供替代格式#section5

当涉及到的图像格式,我们没有了性能和覆盖率之间做出选择。我们可以提供多种选择,让浏览器决定使用哪一个,基于它可以处理。

您可以通过提供多种做到这一点来源图片视频元件。通过建立媒体资产的多种格式开始。例如,WebP的和JPG,它很可能是的WebP将具有比JPG文件较小(但检查以确保)。有了这些替代能源,你可以将它们放入一个图片是这样的:

<图片> < srcset =“我的来源。bb0 图片的描述性文字。 < /图片>

识别浏览器图片元素将检查资源作出决定关于哪个图像到请求之前元件。如果浏览器所支持的MIME类型“图像/ WEBP”,它将开球为的WebP格式图像的请求。如果没有(或如果浏览器不承认图片),它会请求JPG。

这种方法的好处是,您可以为用户提供尽可能小的图像,而不必诉诸于任何JavaScript编程。

你可以采取与视频文件相同的方法:

浏览器的支持的WebM将要求第一资源,而浏览器是鸵鸟政策,但也明白MP4视频,将请求第二个。不支持的浏览器视频元素将回落到有关下载该文件的段落。

顺序的资源元素事宜。浏览器首先会选择可用的资源,因此,如果指定一个优化的替代格式如果是更广泛兼容的格式,替代格式可能永远不会被采用。

根据您的情况,您可以考虑绕过这种基于标记的方法,而在服务器上处理事情。例如,如果请求的是JPG格式,而浏览器支持WebP(在接受头),并没有什么东西与资源的WebP的版本回复阻止你。事实上,一些CDN服务 -Cloudinary,比如,配备这种功能开箱的。

提供不同尺寸# section6

撇开格式不谈,您可能希望提供针对当前浏览器视口大小优化的备用图像大小。毕竟,加载一幅比屏幕渲染大3-4倍的图片是没有意义的;这只是浪费带宽。这就是响应图像进来。

这里有一个例子:

图片描述文字。</code></pre>
        </figure>
        <p>有很多在这个超级充电要去<code>img</code>元素,所以我会打破它:</p>
        <ul>
         <li>这个<code>img</code>为给定的JPG: 256px宽(<code>small.jpg</code>), 512 px wide (<code>medium.jpg</code>)及1024px宽(<code>large.jpg</code>)。这些在<code>srcset</code>与对应的属性<a href=宽度描述符。
         
  • src定义一个默认的图像源,它作为不支持的浏览器的备份srcset。您的默认图像的选择可能会取决于上下文和一般的使用模式。通常我会建议最小的图像是默认的,但如果您的大部分流量是在旧的桌面浏览器,你可能想要去与中等大小的图像。
  • 大小属性是表象提示这告诉浏览器在不同的场景中将如何呈现图像外在大小),一旦CSS被应用。这个例子说明图像将是视口的全宽度(100vw),直到视口宽度达到30em (最小宽度:30em), at which point the image will be 30 em wide. You can make the大小你想要的价值是复杂还是简单;省略它会导致浏览器使用默认值100vw
  • 您甚至可以将此方法与在一个单一的替代格式和作物图片

    所有这一切是说你有很多的工具,在您的处置提供快速加载介质,所以使用它们!

    推迟请求(如果可能)# section7

    几年前,Internet Explorer 11引入了一个新的属性,使开发人员能够降低特定的优先级img元素以加快页面渲染:lazyload。该属性哪儿也不去,标准明智的,但它是一个坚实的企图推迟图像加载到图片中,考虑到(或接近),而不必涉及到的JavaScript。

    从那时起,已经有延迟加载图片的无数的基于JavaScript的实现,但最近谷歌也采取了刺在更声明的方式,使用不同的属性:加载

    加载属性支持三个值(“auto”、“lazy”和“eager”)来定义应该如何引入资源。对于我们的目的,“lazy”值是最有趣的,因为它延迟资源的加载,直到它到达计算距离从视窗。

    把它加入搅拌…

    图片描述文字。</code></pre>
            </figure>
            <p>这个属性在基于chrome的浏览器中提供了一点性能提升。希望它能成为一个标准,并在将来被其他浏览器采用,但同时包含它也没有什么害处,因为不理解该属性的浏览器会简单地忽略它。</p>
            <p>这种方法很好地补充了媒体优先化策略,但在此之前,我想更深入地了解一下服务工作者。</p>
            <h2 id=操纵在服务人员的要求# section8
            

    服务人员是一种特殊类型的网络工作者有能力拦截,修改和响应将通过所有网络请求获取API。他们也可以使用缓存API,以及其它异步客户端数据存储等IndexedDB的资源存储。

    当安装了服务工作人员时,您可以连接到该事件,并在缓存中添加您以后想要使用的资源。许多人利用这个机会来存储全局资产的副本,包括样式、脚本、徽标等,但您也可以使用它来缓存图像,以便在网络请求失败时使用。

    在你的后口袋里放一张备用照片# section9

    假设您想在多个网络配方中使用回退,您可以设置一个命名函数,它将使用该资源响应:

    函数respondWithFallbackImage(){返回缓存。匹配(“/我/回退/离线。svg”);}

    然后,在一个事件处理程序,您可以使用该函数提供回退图像时,图像请求失败时,在网络:

    自我。addEventListener("fetch", event => {const request = event.request;if (request.header .get("Accept").include ("image")) {event。然后(response => {return response;}) .catch(respondWithFallbackImage);}});

    当网络可用时,用户获得预期的行为:

    一个组件的屏幕截图,显示了喜欢某样东西的用户的一系列用户档案图片
    当网络可用预期社交媒体化身渲染。

    但是,当网络中断时,图像将被自动回退交换,用户体验还是可以接受的:

    屏幕截图显示了一系列相同的通用用户图片,而不是没有加载的单个用户图片
    当网络不可用普通的回退化身呈现。

    从表面上看,这种做法似乎不是所有有用的在性能方面,因为你已经基本上增加了一个额外的图像下载到组合。有了这个系统的地方,但是,一些非常惊人的机会开放给你。

    尊重用户的选择保存数据#section10

    有些用户通过输入一个“精简版”模式,或打开“数据保护”功能,减少他们的数据消费。发生这种情况时,浏览器会经常发保存数据与他们的网络请求。

    在您的服务人员,你可以看看这个头,并相应地调整你的回应。首先,您要查找的标题:

    让save_data = FALSE;如果(在导航 '连接'){save_data = navigator.connection.saveData;}

    然后,在您处理图像,你可以选择先发制人地响应与回退图像,而不是去网络:

    self.addEventListener( “读取”,事件=> {常量请求= event.request;如果(request.headers.get( “接受”)包括( “图像”)){event.respondWith(如果(save_data){返回respondWithFallbackImage();} //你以前看到的)代码;}});

    你甚至可以借此更进一步,调respondWithFallbackImage()根据原始请求的目的提供备用映像。为此,您需要在Service Worker中定义几个全局回退:

    const fallback_avatar = "/i/fallbacks/avatar。, fallback_image = "/i/fallbacks/image.svg";

    这两个文件应该在Service Worker安装事件期间缓存:

    返回缓存。addAll([fallback_avatar, fallback_image]);

    最后,内respondWithFallbackImage()你可以成为了基于URL被获取适当的图像。在我的网站中,化身从拉Webmention.io,对于我这样的测试。

    function respondWithFallbackImage(url) {const image =头像。测试(/ webmention \。io /) ?fallback_avatar: fallback_image;返回缓存。匹配(图片);}

    有了这个更改,我需要更新要传入的处理程序request.url作为参数传递给respondWithFallbackImage()。一旦这样做了,当网络被中断我最终看到的是这样的:

    显示一个带有通用用户配置文件图像和图像占位符的博客评论的屏幕截图,其中网络无法加载实际图像
    同时包含化身和嵌入图像将具有两个不同的回退呈现时保存数据报头存在于webmention。

    接下来,当然,我们需要根据实际情况建立一些处理媒体资产的一般准则。

    缓存策略:重点发展某些媒体#section11

    根据我的经验,媒体特别是图像,在网络上一般分为三类必要性。在光谱的一端,是不添加有意义的价值元素。在光谱的另一端是至关重要的资产增加价值,例如对理解周围内容至关重要的图表和图表。介于两者之间的是我所说的“有了就好”的媒体。他们为页面的核心体验增加价值,但对理解内容并不重要。

    如果您考虑您的媒体与这一划分,您可以建立一些一般的指导方针,处理每一种情况,根据情况。换句话说,就是缓存策略。

    媒体加载策略,通过资产是多么重要分解为理解接口
    传媒类 快速连接 保存数据 连接缓慢 没有网络
    危急 加载媒体 使用占位符替换
    很高兴有 加载媒体 使用占位符替换
    非关键 完全删除内容

    当涉及到从多义性的关键不错的到了,这是有帮助的组织到不同的目录(或类似)这些资源。这样,我们可以添加一些逻辑到服务人员,可以帮助它决定哪个是哪个。例如,在我自己的个人网站,关键图像是自托管或来自网站我的书。知道了这些,我可以写正则表达式匹配这些域:

    常量HIGH_PRIORITY = [/aaron\-gustafson\.com/,/adaptivewebdesign\.info/];

    接着就,随即HIGH_PRIORITY变量定义,我可以创建一个函数,让我知道如果一个给定的图像请求(例如)是一个高优先级的请求或没有:

    函数isHighPriority(url){//我们正在处理多少个高优先级链接?令i = high_priority.length;//请求URL是否匹配这个正则表达式?如果(high_priority[我]。test(url)){//是的,它是一个高优先级请求返回true;}} //没有匹配,没有高优先级返回false;}

    添加对媒体请求优先级的支持只需要向事件处理程序,就像我们做的保存数据。您对于网络和缓存处理的具体方法可能会有所不同,但这里是我如何选择在图像请求中混合这种逻辑

    //先检查缓存//如果有,返回缓存的图像//如果图像不在缓存中,继续//这个图像高优先级吗?if (isHighPriority(url)){//获取图像//如果获取成功,保存一个副本在缓存//如果没有,响应一个“离线”占位符//不高优先级}else{//我应该保存数据吗?if (save_data){//响应一个“保存数据”占位符//不保存数据}else{//获取图像//如果获取成功,在缓存中保存一个副本//如果不成功,响应一个“离线”占位符}}

    我们可以将此优先方针多种资产。我们甚至可以用它来控制哪些页面提供高速缓存第一与网络第一。

    保持缓存整洁#section12

    该资源被缓存到磁盘的能力,以控制是一个巨大的机会,但它也包含了一个同样巨大的责任,决不滥用。

    每个缓存策略都可能有所不同,至少有一点不同。例如,如果我们要在线出版一本书,那么缓存所有章节、图片等以供离线浏览是很有意义的。它有固定数量的内容,假设没有大量的图片和视频,用户将受益于不必分别下载每一章。

    在一个新闻网站,然而,高速缓存的每一篇文章和照片很快就会填满我们的用户的硬盘驱动器。如果网站提供的页面和资源的数目不确定,这是至关重要的有一个缓存策略,这对放硬限制多少资源我们缓存到磁盘。

    这样做的一个方法是创建与缓存不同形式的内容相关联的几个不同的块。更短暂的内容缓存可以有大约多少物品可以存放在严格的限制。当然,我们还是可以绑定到设备的存储限制,但我们真的希望我们的网站占用2 GB别人的硬盘?

    这里有一个例子,同样来自我自己的网站:

    常量sw_caches = {静:{名称:`$ {}版本} static`,图片:{名称:`$ {}版本images`,极限:75},网页:{名称:`$ {}版本pages`,极限:5},其他:{名称:`$ {}版本other`,极限:50}}

    在这里,我定义了几个高速缓存,每一个名称用于寻址它在缓存API和a前缀。该在Service Worker的其他地方定义,并允许我在必要时立即清除所有缓存。

    随着的除外静态的缓存,后者用于静态资产,每个高速缓存有限制到可存储项目的数量。我只缓存最近的5页有人访问,例如。图像仅限于最近的75,依此类推。这是一个办法,杰里米·基斯在他的奇书轮廓脱机(它如果你还没有already-你真的应该读这里有一个样本)。

    有了这些缓存的定义,我可以定期清理我的缓存和修剪最早的项目。这里的杰里米对这种方法的推荐代码:

    功能trimCache(cacheName,maxItems){//打开缓存caches.open(cacheName)。然后(缓存=> {//获取键。然后指望他们cache.keys()(键=> {//难道我们具有多于我们应该?如果(keys.length> maxItems){//删除最旧的项目,并运行装饰再次cache.delete(键[0])。然后(()=> {trimCache(cacheName,maxItems)});}});});}

    我们可以触发该代码运行每当一个新的页面加载。通过在服务人员运行它,它运行在一个单独的线程,并不会拖累网站的响应速度。我们通过发布消息触发它(使用的postMessage())从主JavaScript线程发送给服务Worker:

    //首先检查是否有一个活动的服务worker, if (navigator.serviceWorker。然后添加一个事件监听器窗口。addEventListener("load", function(){//告诉服务worker清理navigator.serviceWorker.controller。postMessage(“清理”);});}

    在布线它全部的最后一步是设置服务工接收消息:

    的addEventListener( “消息”,的MessageEvent => {如果(messageEvent.data == “清理”){//循环尽管对于(让sw_caches键缓存){//如果高速缓存有一个限制,如果(sw_caches [键] .limit ==未定义){//它修剪到极限trimCache(sw_caches [键] .name和sw_caches [键] .limit);}!}}});

    在这里,服务工作人员侦听入站消息,并通过运行响应“清理”请求trimCache ()每个高速缓存桶具有限定限制

    这种方法并不优雅,但确实有效。根据每个项的访问频率和/或它在磁盘上占用的空间来决定是否清除缓存的响应会好得多。(仅仅根据缓存的时间来删除缓存项并不是很有用。)遗憾的是,在检查缓存时,我们还没有那么详细的信息。我现在正在努力解决缓存API中的这个限制。

    用户永远是第一位的#section13

    根本进Web应用程序的技术正在不断成熟,但即使你不是在把你的网站成为一个PWA感兴趣,有这么多你可以做今天来改善您的用户体验,当涉及到媒体。而且,与包容性设计的所有其他形式,它开始与您的用户谁是最有在一个可怕的经验,风险居中。

    绘制多余的媒体之间的关键,很高兴到有区别,和。除去多余的内容,然后优化bejeezus出每个剩余资产。服务于多种格式和大小媒体,第一优先的最小版本做出最高延迟和连接速度慢的。如果您的用户说,他们希望保存的数据,尊重和有一个适当的后备计划。缓存明智和对用户的磁盘空间最大的尊重。最后,定期,特别是审计你的缓存策略,当涉及到大型媒体files.Follow这些准则,并从用户 - 摇摆人的一个每一个JioPhone在印度农村移动网络上的人的高端游戏笔记本在硅谷有线到10 Gbps的光纤线路上谷会感谢你的。

    没意见

    有什么要说的吗?

    我们已经关闭了评论,但你可以看到人们说的话,我们没有这样过。

    从阿拉巴马州

    Webwaste

    在《世界垃圾》的这段摘录中,格里·麦戈文研究了膨胀的网站和不必要的资产对环境的影响。
    行业

    连接这些点

    在这段来自创意文化的节选中,Justin Dauer向我们展示了一个组织的文化和设计工作之间相互影响的多种方式。
    事业