Coder Social home page Coder Social logo

articles's People

Watchers

James Cloos avatar Ming Jin avatar

articles's Issues

前端业务使用的缓存

为什么需要缓存

  • 减少延迟
  • 减少网络带宽消耗
  • 减少服务器负载

怎么使用缓存

  • 客户端缓存
  • 服务端缓存

客户端缓存

Application Cache

什么是应用程序缓存(Application Cache)?
HTML5 引入了应用程序缓存,这意味着 web 应用可进行缓存,并可在没有因特网连接时进行访问。

三个优势

  • 离线浏览 - 用户可在应用离线时使用它们
  • 速度 - 已缓存资源加载得更快
  • 减少服务器负载 - 浏览器将只从服务器下载更新过或更改过的资源。

注意事项

  • 浏览器对缓存数据的容量限制可能不太一样(某些浏览器设置的限制是每个站点 5MB)。
  • 如果manifest文件,或者内部列举的某一个文件不能正常下载,整个更新过程都将失败,浏览器继续全部使用老的缓存。
  • 引用manifest的html必须与manifest文件同源,在同一个域下。
  • FALLBACK中的资源必须和manifest文件同源。
  • 当一个资源被缓存后,该浏览器直接请求这个绝对路径也会访问缓存中的资源。
  • 站点中的其他页面即使没有设置manifest属性,请求的资源如果在缓存中也从缓存中访问。
  • 当manifest文件发生改变时,资源请求本身也会触发更新。
  • 系统会自动缓存引用清单文件的 HTML 文件
  • manifest文件中CACHE则与NETWORK,FALLBACK的位置顺序没有关系,如果是隐式声明需要在最前面

个人观点

处理不妥当会导致应用混乱,而且W3C协议已经去除掉该协议了,如果项目没有非必要不建议采用

PWA缓存

Progressive Web App, 简称 PWA,是提升 Web App 的体验的一种新方法,能给用户原生应用的体验。

主要特点

  • 可靠 - 即使在不稳定的网络环境下,也能瞬间加载并展现
  • 体验 - 快速响应,并且有平滑的动画响应用户的操作
  • 粘性 - 像设备上的原生应用,具有沉浸式的用户体验,用户可以添加到桌面

国内支持

[https://lavas.baidu.com/ready/browser?lang=zh]
[https://caniuse.com/#feat=web-app-manifest]
[https://caniuse.com/#search=Cache]
[https://plus.ucweb.com/docs/spm=ucplus.11199946.c-header.6.44cad318HwYtVd]

个人观点

  • PWA对比AppCache而言网络请求有sw作为中间件较为可控
  • 建议采用谷歌提供的工具进行开发会更加得心应手,例如:网络请求优先,缓存优先,只读取缓存,新旧缓存更替删除等功能
  • 可以实现离线支持访问的功能
  • 现阶段浏览器的支持度还不高

localStorage,sessionStorage,memory,cookie

  • localStorage: 没有时间限制的数据存储
  • sessionStorage: 页面会话在浏览器打开期间一直保持,并且重新加载或恢复页面仍会保持原来的页面会话
  • memory: JavaScript变量
  • cookie: 每次请求都会带上对应的值

个人观点

  • localStorage 可以做长期或中短期缓存.
    • 例如:每次存入数据前都设置expire值,用来标明过期时间,下次读取的时先判断expire是否超时,再读取内容
  • sessionStorage 可以做用户当次访问站点缓存,关闭站点后缓存清空.
    • 例如:用户一次性的登录状态,一些临时数据
  • memory 没有触发页面刷新可以一直使用的缓存
    • 例如:当前页面的临时数据刷新或者下次访问均要重新获取的数据
  • cookie 作为全局变量使用
    • 例如: 服务器session功能,自动登录,跟踪用户行为

HTTP缓存

强制缓存

  • HTTP 1.0
    • Expires 浏览器资源缓存过期时间
      • Wed, 30 May 2018 21:01:11 GMT 如果客户端上的时间跟服务器上的时间不一致,那缓存时间可能就没啥意义了
    • Pragma Pragma的优先级是高于Cache-Control
      • no-cache
  • HTTP 1.1
    • Cache-Control 缓存控制
      • no-cache 使用对比缓存来验证缓存数据
      • no-store 所有内容都不会缓存,强制缓存,对比缓存都不会触发
      • max-age=xxx 缓存的内容将在 xxx 秒后失效

Pragma -> Cache-Control -> Expires

对比缓存

  • Last-Modified 服务器在响应请求时,告诉浏览器资源的最后修改时间。

  • If-Modified-Since 再次请求服务器时,通过此字段通知服务器上次请求时,服务器返回的资源最后修改时间

    • 服务器收到请求后发现有头If-Modified-Since 则与被请求资源的最后修改时间进行比对。
    • 若资源的最后修改时间大于If-Modified-Since,说明资源又被改动过,则响应整片资源内容,返回状态码200;
    • 若资源的最后修改时间小于或等于If-Modified-Since,说明资源无新修改,则响应HTTP 304,告知浏览器继续使用所保存的cache
  • Etag 服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识

  • If-None-Match 再次请求服务器时,通过此字段通知服务器客户段缓存数据的唯一标识

    • 服务器收到请求后发现有头If-None-Match 则与被请求资源的唯一标识进行比对
    • 不同,说明资源又被改动过,则响应整片资源内容,返回状态码200
    • 相同,说明资源无新修改,则响应HTTP 304,告知浏览器继续使用所保存的cache

个人观点

能用强制缓存就用�强制缓存,减少带宽和服务器压力,如果更新了资源换个文件名就好啦

服务端缓存

Nginx缓存

Nginx对客户已经访问过的内容在Nginx服务器本地建立副本,这样在一段时间内再次访问该数据,就不需要通过Nginx服务器再次向后端服务器发出请求,所以能够减少Nginx服务器与后端服务器之间的网络流量,减轻网络拥塞,同时还能减小数据传输延迟,提高用户访问速度。同时,当后端服务器宕机时,Nginx服务器上的副本资源还能够回应相关的用户请求,这样能够提高后端服务器的鲁棒性。

配置

  • proxy_cache_path 有两个必填参数,第一个参数为 缓存目录,第二个参数
  • keys_zone keys_zone 指定缓存名称和占用内存空间的大小
  • proxy_cache keys_zone的缓存名称 启用proxy cache,并指定key_zone。另外,如果proxy_cache off表示关闭掉缓存。nginx默认会缓存所有 get 和 head 方法的请求结果,缓存的key默认使用请求字符串
  • proxy_cache_key "$host$request_uri$cookie_user" 自定义key
  • proxy_cache_min_uses 指定请求至少被发送了多少次以上时才缓存,可以防止低频请求被缓存
  • proxy_cache_methods 指定哪些方法的请求被缓存 GET HEAD POST
  • proxy_cache_valid 响应状态码为200 302时,10分钟有效 200 302 10m
  • proxy_no_cache 不生成cache文件
  • proxy_cache_bypass 绕开缓存, 如果任何一个参数值不为空,或者不等于0,nginx就不会查找缓存,直接进行代理转发 $cookie_nocache
  • proxy_cache_use_stale 当作为cache的NGINX收到源站返回error、timeout或者其他指定的5XX错误,并且在其缓存中有请求文件的陈旧版本,则会将这些陈旧版本的文件而不是错误信息发送给客户端 timeout http_500 http_502 http_503 http_504

upstream_cache_status

  • HIT —— 响应包含来自缓存的最新有效的内容
  • EXPIRED —— 缓存中的某一项过期了,来自原始服务器的响应包含最新的内容
  • MISS —— 响应在缓存中找不到,所以需要在服务器中取得。这个响应之后可能会被缓存起来
  • BYPASS —— 响应来自原始服务器而不是缓存,因为请求匹配了一个proxy_cache_bypass,这个响应之后可能会被缓存起来
  • UPDATING —— 内容过期了,因为相对于之前的请求,响应的入口(entry)已经更新,并且proxy_cache_use_stale的updating已被设置
  • REVALIDATED —— proxy_cache_revalidate命令被启用,NGINX检测得知当前的缓存内容依然有效(If-Modified-Since或者If-None-Match)

个人观点

- 如果后端渲染页面需要消耗服务器资源较多的话,考虑针对页面做定时缓存
  - 例如: 请求一个页面需要请求十个�接口并且通过各种计算才能渲染出页面,这时候可以针对该页面做缓存10s,这样子10s内的用户请求就到后端服务器,而是在代理服务器读取缓存即可
- 对静态资源缓存,这样子只要有一个用户访问过该资源,后续所有用户均读取缓存即可

Node缓存

共享内存服务 Redis & Memcached

  1. Redis支持服务器端的数据操作:Redis相比Memcached来说,拥有更多的数据结构和并支持更丰富的数据操作,通常在Memcached里,你需要将数据拿到客户端来进行类似的修改再set回去。这大大增加了网络IO的次数和数据体积。在Redis中,这些复杂的操作通常和一般的GET/SET一样高效。所以,如果需要缓存能够支持更复杂的结构和操作,那么Redis会是不错的选择。
  2. 内存使用效率对比:使用简单的key-value存储的话,Memcached的内存利用率更高,而如果Redis采用hash结构来做key-value存储,由于其组合式的压缩,其内存利用率会高于Memcached。
  3. 性能对比:由于Redis只使用单核,而Memcached可以使用多核,所以平均每一个核上Redis在存储小数据时比Memcached性能更高。而在100k以上的数据中,Memcached性能要高于Redis,虽然Redis最近也在存储大数据的性能上进行优化,但是比起Memcached,还是稍有逊色。
  • [https://yq.aliyun.com/articles/516432?spm=5176.11065265.1996646101.searchclickresult.12e07b20YqOvtX]
  • [https://yq.aliyun.com/articles/79886?spm=5176.11065265.1996646101.searchclickresult.12e07b20YqOvtX]

个人观点

  • redis和memcached对于一般业务使用区别不大,如果需要数据结构多样性用redis,结构简单的用memcached或redis都可以
    -对可以缓存的接口尽量采用缓存,减少io操作,qps可以提升
  • 千人一面的页面也应该采用缓存

服务器内存 Memory

  • 限制内存当缓存,要限制好大小,做好释放
  • 进程之间不能共享内存,所以用内存做缓存也是
  • nodejs在执行JavaScript时,内存受到v8限制,64位约为1.4g,32位0.7g
    垃圾回收时,js线程会暂停执行,大量的堆内存回收严重影响性能

个人观点

-服务器内存对比共享内存而言,性能更高更好更快,因为少了网络请求io操作,但是如果处理不好会出现问题,针对响应时间和处理要求的业务可以考虑使用
-例如:抢购功能

PWA 相关设置 --- manifest

Manifest

引入manifest文件

<link rel="manifest" href="/manifest.json">

Manifest Property

  • name: "name": "Google I/O 2017"

    • 为应用程序提供一个人类可读的名称,例如在其他应用程序的列表中或作为图标的标签显示给用户。
  • short_name: "short_name": "I/O 2017"

    • 为应用程序提供简短易读的名称。这是为了在没有足够空间显示Web应用程序的全名时使用。
  • theme_color: "theme_color": "aliceblue"

    • 定义应用程序的默认主题颜色。这有时会影响操作系统显示应用程序的方式(例如,在Android的任务切换器上,主题颜色围绕着应用程序)。
  • background_color: "background_color": "red"

    • 定义Web应用程序的预期背景颜色。此值重复应用程序样式表中已有的内容,但在样式表加载之前清单可用时,浏览器可以使用此值来绘制Web应用程序的背景颜色。这将启动Web应用程序和加载应用程序内容之间的平滑过渡。
  • start_url: "start_url": "./?utm_source=web_app_manifest"

    • 指定用户从设备启动应用程序时加载的URL。如果以相对URL的形式给出,则基本URL将是清单的URL。
  • orientation: ​​"orientation": "portrait-primary"

    • 应用程序的顶级浏览上下文的默认方向。
    • any
    • natural
    • landscape
    • landscape-primary
    • landscape-secondary
    • portrait
    • portrait-primary
    • portrait-secondary
  • display: "display": "standalone"

    • 显示模式
    • fullscreen 所有可用的显示区域都被使用,并且没有显示用户代理chrome。
    • standalone 该应用程序将看起来像一个独立的应用程序。这可以包括具有不同窗口的应用程序,在应用程序启动器中的它自己的图标等。在这种模式下,用户代理将排除用于控制导航的UI元素,但是可以包括其他UI元素,例如状态栏。
    • minimal-ui 该应用程序将看起来像一个独立的应用程序,但将有一组用于控制导航的UI元素。元素将因浏览器而异。
    • browser 该应用程序在传统的浏览器标签或新窗口中打开,具体取决于浏览器和平台。这是默认的。
  • dir

    "dir": "rtl",
    "lang": "ar",
    "short_name": "أنا من التطبيق!"
    
    • 设置name,short_name和description文字的方向
    • ltr 左到右
    • rtl 右到左
    • auto 默认
  • description: "description": "The app that helps you find the best food in town!"

    • 项目描述
  • scope: "scope": "/myapp/"

    • 定义此Web应用程序的应用程序上下文的导航范围。这基本上限制了应用清单时可以查看的网页。如果用户在范围之外浏览应用程序,则返回到正常的网页。
    • 如果范围是相对URL,则基本URL将是清单的URL。
  • lang: "lang": "en-US"

    • 指定name和short_name成员中的值的主要语言。该值是包含单个语言标记的字符串。
  • icons

    "icons": [
      {
        "src": "icon/lowres.webp",
        "sizes": "48x48",
        "type": "image/webp"
      },
      {
        "src": "icon/lowres",
        "sizes": "48x48"
      },
      {
        "src": "icon/hd_hi.ico",
        "sizes": "72x72 96x96 128x128 256x256"
      },
      {
        "src": "icon/hd_hi.svg",
        "sizes": "72x72"
      }
    ]
    
    • 指定可在各种上下文中用作应用程序图标的图像对象数组。例如,它们可用于在其他应用程序列表中表示Web应用程序,或将Web应用程序与OS的任务切换器和/或系统首选项集成 。
    • sizes 包含空格分隔的图像尺寸的字符串。
    • src 图像文件的路径。如果src是相对URL,则基本URL将是清单的URL。
    • type 提示图像的媒体类型。此成员的目的是允许用户代理快速忽略不支持的媒体类型的图像。
  • prefer_related_applications: "prefer_related_applications": false

    • 指定一个布尔值,提示用户代理向用户指示指定的相关应用程序(请参见下文)可用,并建议通过Web应用程序。只有当相关的本地应用程序确实提供了一些Web应用程序无法做到的事情时,才应该使用它。
  • related_applications:

    "related_applications": [
    {
      "platform": "play",
      "url": "https://play.google.com/store/apps/details?id=com.example.app1",
      "id": "com.example.app1"
    }, {
      "platform": "itunes",
      "url": "https://itunes.apple.com/app/example-app1/id123456789"
    }]
    
    • platform 可以找到应用程序的平台。
    • url 可以找到应用程序的URL。
    • id 用于表示指定平台上的应用程序的ID

Manifest Example

{
  "name": "HackerWeb",
  "short_name": "HackerWeb",
  "start_url": ".",
  "display": "standalone",       
  "background_color": "#fff",
  "description": "A simply readable Hacker News app.",
  "icons": [{
    "src": "images/touch/homescreen48.png",
    "sizes": "48x48",
    "type": "image/png"
  }, {
    "src": "images/touch/homescreen72.png",
    "sizes": "72x72",
    "type": "image/png"
  }, {
    "src": "images/touch/homescreen96.png",
    "sizes": "96x96",
    "type": "image/png"
  }, {
    "src": "images/touch/homescreen144.png",
    "sizes": "144x144",
    "type": "image/png"
  }, {
    "src": "images/touch/homescreen168.png",
    "sizes": "168x168",
    "type": "image/png"
  }, {
    "src": "images/touch/homescreen192.png",
    "sizes": "192x192",
    "type": "image/png"
  }],
  "related_applications": [{
    "platform": "web"
  }, {
    "platform": "play",
    "url": "https://play.google.com/store/apps/details?id=cheeaun.hackerweb"
  }]
}

PWA 相关设置 --- serviceWorker

ServiceWorker

注册worker

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw-test/sw.js', { scope: '/sw-test/' }).then(function(reg) {
    // registration worked
    console.log('Registration succeeded. Scope is ' + reg.scope);
  }).catch(function(error) {
    // registration failed
    console.log('Registration failed with ' + error);
  });
}

安装和激活

this.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open('v1').then(function(cache) {
      return cache.addAll([
        '/sw-test/',
        '/sw-test/index.html',
        '/sw-test/style.css',
        '/sw-test/app.js',
        '/sw-test/image-list.js',
        '/sw-test/star-wars-logo.jpg',
        '/sw-test/gallery/',
        '/sw-test/gallery/bountyHunters.jpg',
        '/sw-test/gallery/myLittleVader.jpg',
        '/sw-test/gallery/snowTroopers.jpg'
      ]);
    })
  );
});

删除旧缓存

this.addEventListener('activate', function(event) {
  var cacheWhitelist = ['v2'];

  event.waitUntil(
    caches.keys().then(function(keyList) {
      return Promise.all(keyList.map(function(key) {
        if (cacheWhitelist.indexOf(key) === -1) {
          return caches.delete(key);
        }
      }));
    })
  );
});

请求拦截

this.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request).catch(function() {
      return fetch(event.request).then(function(response) {
        return caches.open('v1').then(function(cache) {
          cache.put(event.request, response.clone());
          return response;
        });  
      });
    }).catch(function() {
      return caches.match('/sw-test/gallery/myLittleVader.jpg');
    })
  );
});

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.