Vue.js学习

前端性能优化原理与实践(二)

2018-10-28  本文已影响5人  小小的白菜

摘自前端性能优化原理与实践

从 Cookie 到 Web Storage、IndexDB

Cookie

Cookie的本职工作并非本地存储,而是“维持状态”

Web开发的早期,人们亟需解决的一个问题就是状态管理的问题:HTTP 协议是一个无状态协议,服务器接收客户端的请求,返回一个响应,故事到此就结束了,服务器并没有记录下关于客户端的任何信息。那么下次请求的时候,如何让服务器知道“我是我”呢?

在这样的背景下,Cookie 应运而生。

Cookie说白了就是一个存储在浏览器里的一个小小的文本文件,它附着在 HTTP 请求上,在浏览器和服务器之间“飞来飞去”。它可以携带用户信息,当服务器检查Cookie 的时候,便可以获取到客户端的状态。

Cookie的性能劣势
Set-Cookie: name=xiuyan; domain=xiuyan.me

同一个域名下的所有请求,都会携带Cookie。大家试想,如果我们此刻仅仅是请求一张图片或者一个 CSS 文件,我们也要携带一个Cookie 跑来跑去(关键是Cookie里存储的信息我现在并不需要),这是一件多么劳民伤财的事情。Cookie虽然小,请求却可以有很多,随着请求的叠加,这样的不必要的 Cookie带来的开销将是无法想象的。

Web Storage

存储容量大:Web Storage根据浏览器的不同,存储容量可以达到5-10M之间。

仅位于浏览器端,不与服务端发生通信。

Web Storage 核心 API 使用示例

Web Storage保存的数据内容和Cookie一样,是文本内容,以键值对的形式存在。Local StorageSession StorageAPI方面无异,这里我们以localStorage为例:

localStorage.setItem('user_name', 'xiuyan')
localStorage.getItem('user_name')
localStorage.removeItem('user_name')
localStorage.clear()
IndexDB

IndexDB是一个运行在浏览器上的非关系型数据库。既然是数据库了,那就不是5M10M这样小打小闹级别了。理论上来说,IndexDB 是没有存储上限的(一般来说不会小于 250M)。它不仅可以存储字符串,还可以存储二进制数据。

  // 后面的回调中,我们可以通过event.target.result拿到数据库实例
  let db
  // 参数1位数据库名,参数2为版本号
  const request = window.indexedDB.open("xiaoceDB", 1)
  // 使用IndexDB失败时的监听函数
  request.onerror = function(event) {
     console.log('无法使用IndexDB')
   }
  // 成功
  request.onsuccess  = function(event){
    // 此处就可以获取到db实例
    db = event.target.result
    console.log("你打开了IndexDB")
  }
// onupgradeneeded事件会在初始化数据库/版本发生更新时被调用,我们在它的监听函数中创建object store
request.onupgradeneeded = function(event){
  let objectStore
  // 如果同名表未被创建过,则新建test表
  if (!db.objectStoreNames.contains('test')) {
    objectStore = db.createObjectStore('test', { keyPath: 'id' })
  }
}  
  // 创建事务,指定表格名称和读写权限
  const transaction = db.transaction(["test"],"readwrite")
  // 拿到Object Store对象
  const objectStore = transaction.objectStore("test")
  // 向表格写入数据
  objectStore.add({id: 1, name: 'xiuyan'})
// 操作成功时的监听函数
  transaction.oncomplete = function(event) {
    console.log("操作成功")
  }
  // 操作失败时的监听函数
  transaction.onerror = function(event) {
    console.log("这里有一个Error")
  }

服务端渲染的运行机制

相对于服务端渲染,同学们普遍对客户端渲染接受度更高一些,所以我们先从大家喜闻乐见的客户端渲染说起。

客户端渲染

客户端渲染模式下,服务端会把渲染需要的静态文件发送给客户端,客户端加载过来之后,自己在浏览器里跑一遍 JS,根据 JS 的运行结果,生成相应的DOM。这种特性使得客户端渲染的源代码总是特别简洁:

<!doctype html>
<html>
  <head>
    <title>我是客户端渲染的页面</title>
  </head>
  <body>
    <div id='root'></div>
    <script src='index.js'></script>
  </body>
</html>

根节点下到底是什么内容呢?你不知道,我不知道,只有浏览器把 index.js跑过一遍后才知道,这就是典型的客户端渲染。

页面上呈现的内容,你在html源文件里里找不到——这正是它的特点。

服务端渲染

服务端渲染的模式下,当用户第一次请求页面时,由服务器把需要的组件或页面渲染成HTML字符串,然后把它返回给客户端。客户端拿到手的,是可以直接渲染然后呈现给用户的HTML内容,不需要为了生成 DOM 内容自己再去跑一遍 JS代码。

使用服务端渲染的网站,可以说是“所见即所得”,页面上呈现的内容,我们在html源文件里也能找到。

该示例直接将 Vue 实例整合进了服务端的入口文件中:

const Vue = require('vue')
// 创建一个express应用
const server = require('express')()
// 提取出renderer实例
const renderer = require('vue-server-renderer').createRenderer()

server.get('*', (req, res) => {
  // 编写Vue实例(虚拟DOM节点)
  const app = new Vue({
    data: {
      url: req.url
    },
    // 编写模板HTML的内容
    template: `<div>访问的 URL 是: {{ url }}</div>`
  })
    
  // renderToString 是把Vue实例转化为真实DOM的关键方法
  renderer.renderToString(app, (err, html) => {
    if (err) {
      res.status(500).end('Internal Server Error')
      return
    }
    // 把渲染出来的真实DOM字符串插入HTML模板中
    res.end(`
      <!DOCTYPE html>
      <html lang="en">
        <head><title>Hello</title></head>
        <body>${html}</body>
      </html>
    `)
  })
})

server.listen(8080)

实际项目比这些复杂很多,但万变不离其宗。强调的只有两点:

在虚拟 DOM横行的当下,服务端渲染不再是早年JSP 里简单粗暴的字符串拼接过程,它还要求这一端要具备将虚拟 DOM 转化为真实 DOM的能力。与其说是“把 JS 在服务器上先跑一遍”,不如说是“把 Vue、React 等框架代码先在 Node 上跑一遍”

上一篇下一篇

猜你喜欢

热点阅读