web worker 的传值方式以及耗时对比

背景

前一阵子开发的项目 pptx 导入, 由于自己的代码问题,引起了个性能问题,一个 40p 的 pptx 文件,转换成 json 数据,大概要耗时 60s+ ,虽然后面发现是某个使用频率非常高的函数内部,用了 new Function 构造函数 造成的(所以这里顺便提醒一下,如果你很在乎几毫秒的差距的话,建议谨慎使用哈),但是在优化的过程中,一度怀疑是性能达到了瓶颈,所以尝试了使用 web worker 去优化,由于是文件,一般内容都比较大,发现 web worker 在传值这块占用了大部分的时间,所以想开这篇来详细聊聊.

两种传值方式

关于 web worker 的基本用于以及传值方式,网上以及有一大堆介绍了,这里就不赘述了,这里我们重点来看一下同一个文件用两种方式来传值,会有多大的差别,这边随意从电脑里面找了一个 96MB 的 PSD 文件来测试.

主线程

    fetch('./case.psd').then(file => {
            return file.blob();
        })

        .then(blob => {
            return new Promise(resolve => {
                let fileReader = new FileReader();
                fileReader.onload = e => {
                    resolve(e.target.result);
                }
                fileReader.readAsArrayBuffer(blob);
            })
        })

        .then(buf => {
            let worker = new Worker('1.js');

            console.time('计算时间');
            worker.postMessage(buf);

            worker.onmessage = e => {
                console.timeEnd('计算时间');
            }


        })

worker(子)线程, 这里为了避免不必要的因素干扰,worker 线程里面什么也不做,在收到消息后,直接 post 一个消息回去

    self.onmessage = e => {
        postMessage(0);
    }

这边我直接用 FileReader 的 readAsArrayBuffer,读出来是一个长度为 96,138,230 的字符串,长度大概 0.96 亿, 耗时大概 70ms 左右(同一个台电脑取 10 次平均值,下同)

我们稍微改一下上面主线程的代码,改用 转移数据 的方式

- worker.postMessage(buf);

+ worker.postMessage(buf, [buf]);

同样的数据, 耗时大概 17ms 左右,这 17ms 好像是个固定值,我尝试换了个 800MB+ 的文件和一个里面啥都没有的空文本文件,大概都是这个时间.

不同的数据类型,用值传递的耗时也是不一样的

    fetch('./case.psd').then(file => {
            return file.blob();
        })

        .then(blob => {
            return new Promise(resolve => {
                let fileReader = new FileReader();
                fileReader.onload = e => {
                    resolve(e.target.result);
                }
                fileReader.readAsText(blob);
            })
        })

        .then(str => {
            console.log(str.length);
            let worker = new Worker('1.js');

            console.time('计算时间');
            worker.postMessage(str);

            worker.onmessage = e => {
                console.timeEnd('计算时间');
            }


        })

这里我们改用 FileReader 的 readAsText,读出来是一个长度为 95,855,954 的字符串,长度大概 0.95 亿, 耗时大概 118ms 左右,同样我换了上面那个里面啥都没有的空文本文件,耗时也是 17ms 左右.

那我们试试用 readAsDataURL 看看读出来的数据要多久

    fetch('./case.psd').then(file => {
            return file.blob();
        })

        .then(blob => {
            return new Promise(resolve => {
                let fileReader = new FileReader();
                fileReader.onload = e => {
                    resolve(e.target.result);
                }
                fileReader.readAsDataURL(blob);
            })
        })

        .then(str => {
            console.log(str.length);
            let worker = new Worker('1.js');

            console.time('计算时间');
            worker.postMessage(str);

            worker.onmessage = e => {
                console.timeEnd('计算时间');
            }


        })

读出来是一个长度为 128,184,345 的字符串,长度大概 1,28 亿, 耗时大概 85ms 左右(虽然字符串长度更长,但是耗时却更短)

以上耗时,均为主线成向 worker 线程单向传递数据的耗时.

结论

  1. 转移数据几乎是零开销(因为和传递空字符串的耗时是差不多的).
  2. 值传递的话,不同的数据类型,耗时也有差别,ArrayBuffer < base64 < 普通字符串.
  3. postMessage 传递消息,除了发送数据的耗时外,还有其他开销(就是上面的 17ms). 当然每台电脑性能不一样,耗时也是不一样的,不过按比例来看,这个占比还挺大的.

关于转移的缺点, 网上也是有很多的, 这里也就不啰嗦了, 总结一句就是数据无法同时在2个线程上使用.

另外个人觉得如果是普通的数据,为了转移而去转换成 Transferable objects 的话, 大部分情况下是划不来的, 因为你需要在花在编码解码上的时间,会比直接传递花的时间多.

另外, 如果你是要用子线程处理图片的话, ImageBitmap 格式 配合最近新鲜出炉的 OffscreenCanvas 也许是不错的选择.前提是你不需要考虑兼容性问题.

最后是广告时间

我们40人的前端团队常年招兵买马中,在厦门的和想来厦门的童鞋们,不要吝惜你的简历,使劲砸过来 邮箱:nuoya@gaoding.com, 期待你一起来稿事

原文地址 https://github.com/noahlam/ar...

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Vue 3是一种流行的JavaScript框架,因其高效的数据绑定和组件化开发而被广泛使用。而Web Worker是一种浏览器提供的API,用于在主线程之外运行耗时的JavaScript代码。 Vue 3支持Web Worker的主要好处之一是可以将一些耗时的计算任务从主线程中分离出来,这样可以避免长时间运行的代码阻塞用户界面的响应。通过将这些耗时的任务放入Web Worker中,可以使用户在进行其他操作的同时,程序仍然能够运行并持续响应用户的请求。 使用Vue 3的Web Worker可以改善网页性能和用户体验。比如,当网页需要执行大量数据处理或复杂计算时,可以将这些操作放入Web Worker中,确保网页的响应速度不受影响。另外,在Vue 3的开发中,还可以使用Web Worker来处理一些与界面无关的后台任务,如数据的获取和处理,这样可以提高整个应用的稳定性和响应速度。 但是需要注意的是,使用Web Worker也有一些限制和注意事项。首先,Web Worker中不能访问DOM元素,所以如果需要对DOM进行操作,则需要通过消息传递方式Web Worker发送要操作的数据,并由Web Worker处理后再返回结果。其次,Web Worker中无法直接调用Vue实例的方法或直接访问Vue的响应式数据,因此在使用Web Worker时,必须小心处理数据的传递和更新。 综上所述,Vue 3的Web Worker是一种提升应用性能和用户体验的重要工具。通过将一些耗时的计算任务放入Web Worker中,可以避免阻塞用户界面,提高网页的响应速度和稳定性。但使用时需注意一些限制和注意事项,以确保正确地处理数据和更新。 ### 回答2: Vue 3 中的 Web Worker 是一种在后台运行的 JavaScript 脚本,用于提高应用程序的性能并提供更好的用户体验。Vue 3 实现了对 Web Worker 的内置支持,使得开发人员可以轻松地在 Vue 应用程序中使用 Web Worker 进行并行计算和异步操作。 Web Worker 可以在单独的线程中执行耗时的任务,而不会阻塞主线程,以此来提高页面的响应速度。在 Vue 3 中,可以使用 `@vue/web-worker` 插件来管理和使用 Web Worker。 使用 Vue 3 Web Worker,开发人员可以将一些复杂的计算或数据处理的任务放在 Web Worker 中进行,从而将这些任务从主线程中解耦出来。这样做的好处是,我们可以在前端应用程序中更好地利用现代的多核 CPU,并提高应用程序的性能。 在 Vue 3 中使用 Web Worker 的步骤如下: 1. 首先,需要安装 `@vue/web-worker` 插件,并将其添加到项目的依赖项中。 2. 在 Vue 3 的组件中,使用 `createWorker` 函数来创建一个 Web Worker 实例。 3. 通过该实例,我们可以使用 `postMessage` 方法将消息发送给 Web Worker,并使用 `onmessage` 监听来自 Web Worker 的消息。 4. 在 Web Worker 中,我们可以使用 `self.addEventListener('message', (event) => { ... })` 来监听主线程传递的消息,并在需要的时候使用 `postMessage` 向主线程发送消息。 使用 Vue 3 Web Worker 可以很容易地将一些费时的计算任务放在后台线程中运行,保持前端应用的流畅和响应。这对于一些需要大量计算或处理大量数据的应用程序特别有用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值