怎么使用Web Workers提升性能?
Posted IT飞牛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了怎么使用Web Workers提升性能?相关的知识,希望对你有一定的参考价值。
一、概述
Web Workers 使得一个Web应用程序可以在与主执行线程分离的后台线程中运行一个脚本操作。这样做的好处是可以在一个单独的线程中执行费时的处理任务,从而允许主(通常是UI)线程运行而不被阻塞。
它的作用就是给JS创造多线程运行环境,允许主线程创建worker线程,分配任务给后者,主线程运行的同时worker线程也在运行,相互不干扰,在worker线程运行结束后把结果返回给主线程。这样做的好处是主线程可以把计算密集型或高延迟的任务交给worker线程执行,这样主线程就会变得轻松,不会被阻塞或拖慢。这并不意味着JS语言本身支持了多线程能力,而是浏览器作为宿主环境提供了JS一个多线程运行的环境。
不过因为worker一旦新建,就会一直运行,不会被主线程的活动打断,这样有利于随时响应主线程的通性,但是也会造成资源的浪费,所以不应过度使用,用完注意关闭。或者说:如果worker无实例引用,该worker空闲后立即会被关闭;如果worker实列引用不为0,该worker空闲也不会被关闭。
二、使用场景
前端过程中,如果遇到一些大量耗时的运用场景,我们可以采用web worker,新建线程,来提升主线程的运行流畅性,提升性能。可能场景如下:
-
加密数据
有些加解密的算法比较复杂,或者在加解密很多数据的时候,这会非常耗费计算资源,导致UI线程无响应,因此这是使用Web Worker的好时机,使用Worker线程可以让用户更加无缝的操作UI。
-
预取数据
有时候为了提升数据加载速度,可以提前使用Worker线程获取数据,因为Worker线程是可以是用
XMLHttpRequest
的。 -
预渲染
在某些渲染场景下,比如渲染复杂的canvas的时候需要计算的效果比如反射、折射、光影、材料等,这些计算的逻辑可以使用Worker线程来执行,也可以使用多个Worker线程,这里有个射线追踪的示例。
-
复杂数据处理
某些检索、排序、过滤、分析会非常耗费时间,这时可以使用Web Worker来进行,不占用主线程。
-
预加载图片
有时候一个页面有很多图片,或者有几个很大的图片的时候,如果业务限制不考虑懒加载,也可以使用Web Worker来加载图片,可以参考一下这篇文章的探索,这里简单提要一下。
三、语法
Worker()
构造函数创建一个 Worker
对象,该对象执行指定的 URL 脚本。这个脚本必须遵守 同源策略 。
const myWorker = new Worker(aURL, options);
1、参数
-
如果文档不允许启动 worker,则会引发 SecurityError
-
如果脚本之一的 MIME 类型为
text/csv
,image/*
,video/*
,或audio/*
, 则会引发 NetworkError。它应该始终是 text/javascript。 -
如果 aURL 无法解析,则引发 SyntaxError。
-
aURL
- : 是一个
DOMString
表示 worker 将执行的脚本的 URL。它必须遵守同源策略。
- : 是一个
-
options
可选
- : 包含可在创建对象实例时设置的选项属性的对象。可用属性如下:
type
:用以指定 worker 类型的DOMString
值。该值可以是classic
或module
. 如果未指定,将使用默认值classic.
credentials
:用以指定 worker 凭证的DOMString
值。该值可以是*omit
*,same-origin
,或include
.。如果未指定,或者 type 是classic
,将使用默认值omit
(不要求凭证)。- *
name
:*在DedicatedWorkerGlobalScope
的情况下,用来表示 worker 的 scope 的一个DOMString
值,主要用于调试目的。
- : 包含可在创建对象实例时设置的选项属性的对象。可用属性如下:
2、返回值
创建的 worker。
五、使用
1、常驻内存
index.vue代码:
<template>
web worker
<el-button @click="save" type="primary">保存</el-button>
</template>
<script setup lang="ts">
import onMounted from "vue";
const saveWorker = new Worker(
new URL("./worker.ts", import.meta.url),
type: "module",
);
saveWorker.onmessage = (e: any) =>
if (e.data.error)
console.error("自动保存失败,请联系管理员!");
else
console.log("自动保存成功!");
;
const save = () =>
saveWorker.postMessage(
frameData: a: 1, b: 2 ,
editorToken: "123456",
);
onMounted(() =>
)
</script>
<style lang="scss"></style>
worker.ts代码:
import axios from "axios";
self.addEventListener("message", async (e) =>
const frameData = e.data.frameData;
const token = e.data.editorToken;
let params = frameData, token ;
let res = await axios(
url: "/api/get",
method: "get",
params: params,
)
if (res.data.code !== 0)
// worker线程发送消息
(self as any).postMessage(
error: true,
);
return;
// worker线程发送消息
(self as any).postMessage(
error: false,
data: res.data.data
);
);
export ;
2、临时使用
index.vue代码:
//index.vue
<template>
web worker
<el-button @click="save" type="primary">保存</el-button>
</template>
<script setup lang="ts">
import onMounted from "vue";
const save = () =>
//每次使用都单独创建
const saveWorker = new Worker(
new URL("./worker.ts", import.meta.url),
type: "module",
);
saveWorker.onmessage = (e: any) =>
if (e.data.error)
console.error("自动保存失败,请联系管理员!");
else
console.log("自动保存成功!");
;
saveWorker.postMessage(
frameData: a: 1, b: 2 ,
editorToken: "123456",
);
onMounted(() =>
)
</script>
<style lang="scss"></style>
worker.ts代码:
//worker.ts
import axios from "axios";
self.addEventListener("message", async (e) =>
//...同上
(self as any).close();//用完就关闭
);
export ;
六、使用限制
worker线程的使用有一些注意点
- 同源限制
worker线程执行的脚本文件必须和主线程的脚本文件同源,这是当然的了,总不能允许worker线程到别人电脑上到处读文件吧 - 文件限制
为了安全,worker线程无法读取本地文件,它所加载的脚本必须来自网络,且需要与主线程的脚本同源 - DOM操作限制
worker线程在与主线程的window不同的另一个全局上下文中运行,其中无法读取主线程所在网页的DOM对象,也不能获取document
、window
等对象,但是可以获取navigator
、location(只读)
、XMLHttpRequest
、setTimeout族
等浏览器API。 - 通信限制
worker线程与主线程不在同一个上下文,不能直接通信,需要通过postMessage
方法来通信。 - 脚本限制
worker线程不能执行alert
、confirm
,但可以使用XMLHttpRequest
对象发出ajax请求。
以上是关于怎么使用Web Workers提升性能?的主要内容,如果未能解决你的问题,请参考以下文章