[譯] 用 Web Worker 改善 Vue 組件性能

原文: vuedose.tips/use-web-wor…javascript

有時開發者須要和一些「很重」的組件打交道 -- 這一般是指因爲執行了複雜的任務,因此建立和渲染開銷都很大的組件。html

比方說,我昨天就在使用「StoryBlok」工具庫建立富文本編輯器的時候遇到了麻煩。前端

事情是這樣的,從 StoryBlok API 獲取富文本內容的時候,獲得的數據有其獨有的結構。爲了將這種數據渲染到 HTML 中,就必須使用 storyblok-js-client 庫提供的 richTextResolver.render(content) 方法。vue

咱們能夠將這個功能封裝到一個 RichText.vue 組件中。一種基本的實現多是:java

<template>
  <div v-html="contentHtml"></div>
</template>

<script> export default { props: ["content"], computed: { contentHtml() { // $storyapi 是來自於 StoryBlok Nuxt.js 模塊中的一個實例 return this.$storyapi.richTextResolver.render(content); } } }; </script>
複製代碼

至此彷佛平淡無奇,但...驚雷⚡️不期而至。web

看上去,把這些內容渲染出來但是個繁重的工做,這在 StoryBlok 的各類組件開始渲染包含大量內容的數據時尤其明顯。npm

如今再想象這樣的場景:你的頁面上有個包含富文本組件的列表,以及一個下拉篩選器。當你改變篩選項時,將從新請求符合篩選的全部內容,再把列表項都從新渲染一遍。api

實際運行後你還將看到 richTextResolver.render 帶來的渲染負擔:篩選下拉框在被選擇值後的關閉動做很是遲緩。瀏覽器

緣由就在於默認的 JavaScript 運行在主線程,也就是被稱做 UI-blocking 的問題。bash

問題是理解了,但...如何解決呢?其實也很簡單:爲富文本渲染任務使用一個 Web Worker 就好了。

若是要對 JS 單線程和 Web Worker 有所瞭解,請閱讀:

Web Worker 運行在一個獨立的線程中,且不會形成 UI 阻塞,很是適於咱們的用例。

worker-loader 插件

更多的技術細節請閱讀上面的連接,這裏只要知道 Web Worker 運行在自有的上下文中,而且默認狀況沒法訪問外部上下文就好了。但本例中咱們要訪問到 storyblok-js-client npm 模塊。對此,能夠用 Webpack 中的 worker-loader 解決。

首先用 npm install -D worker-loader 安裝依賴。而後須要對其配置,好比在本例中的 Nuxt.js 中像這樣配置 nuxt.config.js :

build: {
  extend(config, { isDev, isClient }) {
    config.module.rules.push({
      test: /\.worker\.js$/,
      use: { loader: "worker-loader" }
    });
  }
}
複製代碼

這樣一來,全部 .worker.js 結尾的文件都將被 worker-loader 註冊爲 Web Worker

下面建立一個 render-html.worker.js

import StoryblokClient from "storyblok-js-client";

let storyClient = new StoryblokClient({});

self.addEventListener("message", ({ data }) => {
  const result = storyClient.richTextResolver.render(data);
  self.postMessage(result);
});
複製代碼

這就是一個 worker 的基礎實現。須要監聽 message 事件,這也正是與你的 Vue.js 應用通信的方式。當你從事件中獲得 data 後,用 storyblok-js-client 渲染該數據,並將獲得的結果用 self.postMessage 回傳。

接着來升級一下 RichText.vue 組件,以使用以上 worker :

<template>
  <div v-html="contentHtml"></div>
</template>

<script>
  import Worker from "./render-html.worker.js";

  const worker = new Worker();

  export default {
    props: ["content"],
    data: () => ({
      contentHtml: ""
    }),
    mounted() {
      // 等待處理好的 HTML 內容,並更新到狀態中
      worker.onmessage = ({ data }) => {
        this.contentHtml = data;
      };
      // 將原始內容傳遞給 worker 渲染
      worker.postMessage(this.content);
    }
  };
</script>
複製代碼

結果

你確定很好奇,通過這一番折騰,性能上有何改善呢?看看就知道了。

在 main.js 等處設置 Vue.config.performance = true 後,在 Chrome DevTools 裏的 performance 選項卡中可查看性能監測數據。

結果分別是:組件渲染(建立 VDom 結構的時間)快了 20.65 倍、patch(將 VDom 結構應用到 DOM 上的時間)快了 1.39 倍。



--End--

查看更多前端好文
請搜索 fewelife 關注公衆號

轉載請註明出處

相關文章
相關標籤/搜索