web worker 前端多线程一、

前言: JavaScript 语言采用的是单线程模型,也就是说,所有任务只能在一个线程上完成,一次只能做一件事。前面的任务没做完,后面的任务只能等着。随着电脑计算能力的增强,尤其是多核 CPU 的出现,单线程带来很大的不便,无法充分发挥计算机的计算能力。

最近在做vue的项目中,遇到了计算量庞大导致页面响应缓慢的问题,正好每个计算任务的结果不需要汇总,所以想到了以多线程的形式去执行每个计算任务。但是通过一轮google、baidu都没有找到vue的案例,最后发现web worker可以做多线程。

Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。在主线程运行的同时,Worker 线程在后台运行,两者互不干扰。等到 Worker 线程完成计算任务,再把结果返回给主线程。这样的好处是,一些计算密集型或高延迟的任务,被 Worker 线程负担了,主线程(通常负责 UI 交互)就会很流畅,不会被阻塞或拖慢。

Worker 线程一旦新建成功,就会始终运行,不会被主线程上的活动(比如用户点击按钮、提交表单)打断。这样有利于随时响应主线程的通信。但是,这也造成了 Worker 比较耗费资源,不应该过度使用,而且一旦使用完毕,就应该关闭。

Web Worker 有以下几个使用注意点:

(1)同源限制

分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。

(2)DOM 限制

Worker 线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的 DOM 对象,也无法使用documentwindowparent这些对象。但是,Worker 线程可以navigator对象和location对象。

(3)通信联系

Worker 线程和主线程不在同一个上下文环境,它们不能直接通信,必须通过消息完成。

(4)脚本限制

Worker 线程不能执行alert()方法和confirm()方法,但可以使用 XMLHttpRequest 对象发出 AJAX 请求。

(5)文件限制

Worker 线程无法读取本地文件,即不能打开本机的文件系统(file://),它所加载的脚本,必须来自网络。

介绍了这么多的web worker 的知识,不如来点案例看看。

案例:

正常我们洗澡后才洗衣服对吧,js执行的话也只能一步步执行,先干啥,在干啥。

1、洗完澡后再洗衣服: 在没有洗衣机(Worker)前,通常都是先洗完澡后再手洗衣服,这样我们每天都要花费不少时间在洗澡和洗衣服上,花费时长为:洗澡所用时长+洗衣服所用时长。相当于下面这段代码:

javascript 复制代码
console.time('一共花了多少时长')
console.time('洗澡所用时长')
let length_1 = 300000000;
let sum1 = 0
for (let i = 0; i <= length_1; i++) {
    sum1 += i
}
console.log('%c循环1执行完:' + sum1, 'color:green')
console.timeEnd('洗澡所用时长')
console.time('洗衣服所用时长')
let length_2 = 200000000;
let sum2 = 0
for (let i = 0; i <= length_2; i++) {
    sum2 += i
}
console.log('%c循环2执行完:' + sum2, 'color:green')
console.timeEnd('洗衣服所用时长')
console.timeEnd('一共花了多少时长')

打印结果:

(从结果可以看到大概第2.7秒循环1执行完了,接着大概到了第4.5秒后循环2才执行完,所以从中可以看出循环1阻塞了循环2,所以此时花费时长为:循环1+循环2)

2、把衣服放到洗衣机后洗澡: 当我们拥有洗衣机(Worker)后,就可以把衣服放到洗衣机后愉快的洗澡了,此时为异步操作,那么这时花费的总时长取决于谁更后洗完了,花费时长为:Math.max(洗澡所用时长,洗衣服所用时长)。相当于下面的代码:

现在本地建个文件夹 里面放 :

|-index.html

|-worker.js

index.html:

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Web Worker</title>
</head>

<body>

</body>
<script>
    console.time('洗衣机洗完衣服了,所用时长')
    let worker = new Worker("./worker.js"); // 开启副线程
    let length_1 = 300000000;
    let sum1 = 0
    worker.postMessage(length_1); // 发送消息给副线程
    worker.onmessage = e => { // 监听副线程返回的消息
        sum1 = e.data
        console.log('%c循环1执行完了:' + e.data, 'color:green')
        console.timeEnd('洗衣机洗完衣服了,所用时长')
        worker.terminate() // 关闭线程
    }
    console.time('洗完澡了,所用时长')
    let length_2 = 200000000;
    let sum2 = 0
    for (let i = 0; i <= length_2; i++) {
        sum2 += i
    }
    console.log('%c循环2执行完了:' + sum2, 'color:green')
    console.timeEnd('洗完澡了,所用时长')
</script>

</html>

worker.js:

javascript 复制代码
self.onmessage = function (e) { //监听主线程发过来的消息
    let length_1 = e.data
    let sum = 0
    for (let i = 0; i <= length_1; i++) {
        sum += i
    }
    self.postMessage(sum); // 将信息发送到主线程上
}

从结果可以看到大概第1.9秒循环2执行完了,紧接着接着大概第2.4秒后循环1也执行完了,当我们把循环1放到线程上执行时并没有阻塞后续的循环2,因为循环2循环时长短所以先打印出来了,因此此时花费总时长为:循环1。

注: 由于谷歌浏览器不支持读取本地文件,浏览器出于安全考虑,不允许直接从file:///协议加载Web Worker脚本。这是因为本地文件系统路径(如file:///)可能被恶意软件利用来执行不受信任的代码。

解决方法:

1、 设置允许访问本地文件

只需要右键谷歌浏览器的快捷方式,查看属性,在目标一栏中空出一格 然后加入字符串**--allow-file-access-from-files**,先点应用,再点击确定即可。

2、 允许跨域请求

建议再创建一个新的谷歌浏览器的快捷方式,与之前的快捷方式区分开,在想使用跨域请求的时候打开新的快捷方式,保证上网安全。

先在磁盘上创建一个无关紧要的文件夹,你应该也可以指定一个已经存在的文件夹,复制文件夹的路径,在目标一栏中加入--user-data-dir="YourDirectory" --disable-web-security,注意把YourDirectory替换成你新建或者指定的目录。点击保存后打开快捷方式,如何出现下图提示,则表示设置成功,就可以进行跨域请求了。

然后就是设置: 你需要开发用的文件夹目录的路径

然后把你上一步添加的目标位置的 字符串,换成这个(里面含有必须要读取的文件夹目录位置)

javascript 复制代码
--allow-file-access-from-files --user-data-dir="C:\你需要读取的文件夹的名字"

总结:最后虽然折腾这么久后只省了几秒钟,但是当项目计算量越来越大,多线程的优势就会变得特变明显了。

下一篇主要来讲解一下,web worker在 vue里面怎么使用。
相关推荐
猫猫村晨总8 天前
前端图像处理实战: 基于Web Worker和SIMD优化实现图像转灰度功能
前端·图像处理·vue3·canvas·web worker
c.6 个月前
XLSX + LuckySheet + LuckyExcel + Web Worker实现前端的excel预览
前端·javascript·excel·web worker
heroboyluck7 个月前
Web Worker 学习及使用
前端·javascript·web worker
这么近又那么远10 个月前
vue2使用webSocket双向通讯
websocket·vue·web worker
朝闻道-夕可死1 年前
offscreenCanvas+worker+IndexedDB实现无感大量图片缓存
canvas·js·indexeddb·canvastexture·offscreencanvas·transferable objects·web worker