zoukankan      html  css  js  c++  java
  • 【GISER&&前端优化】前端缓存的几种主流选择

      这周遇到了一个新需求,产品反馈地图瓦片服务的图片资源没有Http缓存,每次移动地图范围都会向后台发处请求/响应数据,影响了客户端的地图加载体验。所以需要增加这样一种缓存:1)针对同一个请求资源地址URL,首次加载需要缓存数据,后续加载直接读取缓存;2)后台数据发生更新时,需要实时更新缓存;
      在完成这个需求之前,我借机补习了一下前端的缓存体系:

    一  HTTP缓存
      提起前端缓存,首先第一反应就是浏览器自带的缓存机制,通过在Http报文头部中设置一些属性字段,告知浏览器对本次请求响应的资源进行缓存,之后对于相同URL的资源请求则直接从缓存中读取。这个思路没错,那具体应该如何实现呢?这就需要我们对这些属性进行简单介绍一下:

      1  强缓存
       首次请求资源A设置缓存,再次请求资源A时直接查找缓存,如果缓存命中,则不发送新的请求;否则发送新请求;
       控制强缓存的主要属性字段:
        【Expire】:HTTP1.0标准下的字段,指定一个日期或时间,在时间过期前执行上述逻辑,时间过期后重新执行
        【Cache-Control】:
          field description
          private 仅客户端缓存
          public 客户端和代理服务器缓存
          max-age=xxx 缓存内容将在xxx秒后失效(相对请求时间)
          s-max-age 仅适用于public共享缓存
          no-cache 需要使用协商缓存来验证缓存(会发送新的请求)
          no-store 所有内容都不缓存
          must-revalidate

      2 协商缓存
      顾名思义,由服务端协助客户端实现缓存机制:即在资源B已缓存的前提下,再次请求资源B时,会继续想服务器端发送请求,通过服务器发送请求,获取资源B是否失效的信息,如果未失效,返回未失效Flag告知前端,从而在缓存中获取资源B,如果失效,则返回新的数据和报文缓存头设置;
    常用的协商缓存包括:
      【Cache-Control的must-revalidate】:标识每次必须向服务端请求验证资源

      【Etag】-【if-none-match】:资源的唯一标识,即在第一次请求资源C时,会计算一个能够唯一标识当前资源C的tag值,并放在response的Etag属性字段中,当资源C缓存在前端后,后续的每一次请求资源C都会将tag值设置在请求request的if-none-match中,服务端根据tag值进行判断当前请求资源C是否发生变化,如变化这表示缓存未命中,返回新的资源C,否则返回缓存命中标识,直接返回304获取资源C在前端的缓存。

      【last-modified】-【if-modified-since】:同上Etag,只不过此处一般以时间戳作为判断依据,服务端则需要获取资源C的文件最后修改时间(这个在JAVA中File提供了getLastModified方法),并将时间戳赋值给response中的last-modified属性字段,后续的每一次请求会将时间戳放在if-modified-since中,与后台的新时间戳对比,如果时间戳不同,则表示缓存未命中,返回新的资源C,否则返回缓存命中标识,前端获取缓存值;

      3 实现
      OK,梳理完上述的Http缓存机制后,我们很容易发现如果要满足需求(即客户端缓存数据,且能够在数据发生变化后请求返回新的数据,更新缓存),应当选择协商缓存。
    策略选择好之后,实现还是比较简单的,我们这里以时间戳为例:
      3.1)  后台在返回数据时增加时间戳判断:

    Public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
    //......
      String filePath
    = ""; //   File fileC = new File(filePath);   long lastNew = fileC.lastModified();   String lastNewStr = Long.toString(lastNew); //获取当前资源的最后修改时间   String lastOldStr = request.getHeader("if-modified-since"); //获取当前资源缓存的最后修改时间   if(lastNewStr.equalsIgnoreCase(lastOldStr)){     Response.setStatus(304); //返回304 not modified   }else{   //获取新的数据   } // ...... }

      3.2) 验证效果
      效果比较尴尬,因为在实现了这类缓存后,请求响应资源的效率提高并不明显,虽然实现了缓存,但是每次资源校验依然要经过一次完整的请求响应过程,其中的连接开销应该是耗时的主要部分,而非数据的传输。所以,只能临时更改策略,采用期限强缓存,后台如果更新数据,则需要客户端手动刷新缓存。

      实现方法如下,采用Cache-Control的max-age,以一天时间为缓存期限:

    Public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
      //…
      response.setHeader("Cache-Control", "max-age=86400");
      //…
    }

    二  前端数据库缓存
      在完成这个任务后,我突然想起来之前在完成矢量地图渲染时,为了提高前端中文字体加载效率,曾经使用过前端数据库indexDB作为缓存技术,这个和Http缓存又有什么不同呢?一般来说,前端数据库主要有一下几种:
      1 cookie
      常用场景:用户个人信息保存(用户名/密码)
      存在问题:
        容量:4KB
        数据安全问题

      2 localStorage/sessionStorage【键值对】:本地浏览器数据库,根据浏览器不同,缓存容量不同,一般5MB左右,适合存储一些常用结构简单的数据;
        localStorage.setItem("key", "value")
        localStorage.getItem("key")
        localStorage.removeItem("key")
        localStorage.clear()
      优势场景:
        兼容性好,易操作
      缺点:
        容量小,每个域名分配3-5M空间

      3 indexedDB【结构化对象】:本地数据库存储,使用索引高效检索,异步处理;
      优势场景:
        a 异步操作,可大量读写数据而不阻塞浏览器主线程
        b 支持事务
        c 存储空间大(250MB->更多)
        d 支持二进制存储ArrayBuffer和Blob
      缺点:
        操作比较繁琐复杂,不如localStorage方便
      实现:
        var databaseName = "test"
        var version = "20191121"
        var request = window.indexedDB.open(databaseName, version) //创建一个indexedDB数据库
      具体操作略微有些复杂,需要熟悉相关API接口,此处就不作详细介绍了,具体可以参照阮一峰的教程;

    三  比较
      比较Http缓存和前端数据库缓存,暂时没有发现这些缓存有什么明显的差异,只是针对应用场景不同而已:
      1)Http缓存一般能够缓存一些前端请求的一些公共资源,减少一些不必要的请求响应开销,提高web端的体验
      2)而前端数据库缓存则能够缓存一些高频常用的业务数据,提高业务请求的数据返回速度,比如高德地图和百度地图: 【高德地图】:打开Chrome控制台的Application选项卡,可以查看IndexedDB中的数据,其中包含了road/region等矢量瓦片数据;  【百度地图】:打开IndexedDB空空如也,但是在LocalStorage中发现了一些POI搜索记录;并且百度地图的矢量数据服务利用了Cache-Control属性强缓存了矢量数据,从而减小实时的数据请求。

  • 相关阅读:
    Asp.net中文本框全选的实现
    如何在Sql Server中读取最近一段时间的记录,比如取最近3天的或最近3个月的记录。
    asp.net存储过程分页+GridView控件 几百万数据 超快
    Gridview各种功能+AspNetPager+Ajax实现无刷新存储过程分页 (留着用)
    asp.net导出EXCEL的好方法!(好用,导出全部数据)
    GridView分页的实现 ASP.NET c#(转)特好用
    asp.net c# repeater或gridview导出EXCEL的详细代码。
    c#实现word,excel转pdf代码及部分Office 2007文件格式转换为xps和pdf代码整理
    C# WORD操作实现代码(转载)
    如何提高程序员的生产率 (2)
  • 原文地址:https://www.cnblogs.com/escage/p/11907269.html
Copyright © 2011-2022 走看看