原文: 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 阻塞,很是適於咱們的用例。
更多的技術細節請閱讀上面的連接,這裏只要知道 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 倍。
查看更多前端好文
請搜索 fewelife 關注公衆號
轉載請註明出處