Leecason

vuePress-theme-reco Leecason    2018 - 2020
Leecason Leecason

Choose mode

  • dark
  • auto
  • light
主页
分类
  • CSS
  • FrontEnd
  • GraphQL
  • JavaScript
  • TypeScript
  • Vue
  • Webpack
  • 其它
  • 数据结构与算法
  • 浏览器相关
标签
时间线
GitHub
author-avatar

Leecason

80

Article

61

Tag

主页
分类
  • CSS
  • FrontEnd
  • GraphQL
  • JavaScript
  • TypeScript
  • Vue
  • Webpack
  • 其它
  • 数据结构与算法
  • 浏览器相关
标签
时间线
GitHub

「译」 VueDose Tip 33 - 在 Vue.js 组件中使用 Web Worker 获得极致性能

vuePress-theme-reco Leecason    2018 - 2020

「译」 VueDose Tip 33 - 在 Vue.js 组件中使用 Web Worker 获得极致性能

Leecason 2020-04-18 Vue 2Vue 3VueDose文章翻译

在第一篇文章中,我展现了一个技巧来提高 Vue 中大型列表的性能,这是一个很好的开始。

但是并非所有情况都如此。

有时你需要创建繁重的组件来渲染,通常是因为它们所对应的业务功能比较复杂。昨天我遇到了一个类似的情景。

我正在使用 StoryBook 创建页面。它们具有创建富文本字段的惊人的功能,内容管理员可以使用该字段来输入任何形式的文本,例如图片,块引用,加粗,斜体等。

当你从 Story Book API 获取富文本内容时,它有自己的数据结构,为了将数据渲染为 HTML,你必须使用 storyblok-js-client 的 richTextResolver.render(content) 方法。

我们可以将此功能封装到 RichText.vue 组件中,基础结构为:

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

<script>
  export default {
    props: ["content"],
    computed: {
      contentHtml() {
        return this.$storyapi.richTextResolver.render(content);
      }
    }
  };
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

注意: $storyapi 是 StoryBlok Client的一个实例,该实例来自 StoryBlock Nuxt 模块,这是我正在使用的模块,但这与本文的主题无关

到目前为止还没有什么特别的。

惊喜来了。

渲染似乎是一项繁重的任务,当渲染具有相当数量的这个组件时,就要开始引起注意了。

现在想象一下:页面中有一个富文本组件列表,还有一个下拉列表来过滤,当更改下拉列表的过滤选项时,你将重新获取该过滤条件下的内容,并且重新渲染。

这里你可能会注意到 richTextResolver.render 的繁重: 当选择过滤值后,下拉列表滞后关闭。

原因是默认的 JavaScript 执行在阻塞 UI 渲染的主进程中。

问题清楚了以后,现在该如何解决?

简单:使用 Web Worker 进行富文本渲染任务。

注意:我不会深入 Web Worker,请查看其文档 获取它的一些信息

Web Workers 在单独的线程中运行,并不阻塞 UI 渲染,非常适合我们的情况。

请记住,Web Worker 是在自己的上下文中运行的,默认情况下,我们无法访问外部的上下文。但是我们需要访问 storyblok-js-client npm 模块,为此,Webpack 提供了 worker-loader。

首先,运行 npm install -D web-worker 来安装,然后需要对其进行配置。在 Nuxt.js 中,可以通过 nuxt.config.js 来配置:

build: {
  extend(config, { isDev, isClient }) {
    config.module.rules.push({
      test: /\.worker\.js$/,
      use: { loader: "worker-loader" }
    });
  }
}
1
2
3
4
5
6
7
8

使用此配置,所有的 *.worker.js 将由 web-worker 处理。

接下来创建一个 render-html.worker.js:

import StoryblokClient from "storyblok-js-client";

let storyClient = new StoryblokClient({});

// When the parent theard requires it, render the HTML
self.addEventListener("message", ({ data }) => {
  const result = storyClient.richTextResolver.render(data);
  self.postMessage(result);
});
1
2
3
4
5
6
7
8
9

这是一个 worker 的基础实现。你需要监听 message 事件,这是一个从 Vue.js 应用程序中与它通信的方式。然后,你可以获取从事件中获取 data,使用 storyblok-js-client 来渲染并使用 self.poseMessage 发送结果。

接下来更新 RichText.vue 组件来使用 service worker:

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

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

  // Create the worker instance
  const worker = new Worker();

  export default {
    props: ["content"],
    data: () => ({
      contentHtml: ""
    }),
    mounted() {
      // Update the state with the processed HTML content
      worker.onmessage = ({ data }) => {
        this.contentHtml = data;
      };
      // Call the worker to render the content
      worker.postMessage(this.content);
    }
  };
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 结果

你是否想知道由此我们获得了多少性能提升?当然,如果不进行衡量,Web Performance 将毫无意义。

实际上,我有一篇文章供你学习和了解如何衡量 Vue.js组件中的性能 。因此,请务必阅读以更好的理解以下测试。

结果是:组件 render 快了 20.65 倍,组件 patch 快了 1.39 倍。

web_worker_render_improvement

web_worker_patch_improvement

如果你不知道 render 和 patch 的含义,在这篇文章 中有说明。

# 原文链接