webwork详细攻略,在vue中使用和加载静态文件

您所在的位置:网站首页 甲状腺手术疤痕图片 webwork详细攻略,在vue中使用和加载静态文件

webwork详细攻略,在vue中使用和加载静态文件

2023-05-29 19:37| 来源: 网络整理| 查看: 265

前言

项目中需要进行模型上传场景的过程中,再开一个线程去进行模型压缩为drc类型,这个时候需要Web Worker构建多线程环境,再次做一个简单总结

1、概述

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

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

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

1.1、使用限制

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

(1)同源限制

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

(2)DOM 限制

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

(3)通信联系

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

(4)脚本限制

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

(5)文件限制

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

2、基本用法 2.1、主线程

主线程采用new命令,调用Worker()构造函数,新建一个 Worker 线程。

var worker = new Worker('work.js'); 复制代码

Worker()构造函数的参数是一个脚本文件,该文件就是 Worker 线程所要执行的任务。由于 Worker 不能读取本地文件,所以这个脚本必须来自网络。如果下载没有成功(比如404错误),Worker 就会默默地失败。

然后,主线程调用worker.postMessage()方法,向 Worker 发消息。

worker.postMessage('Hello World'); worker.postMessage({method: 'echo', args: ['Work']}); 复制代码

worker.postMessage()方法的参数,就是主线程传给 Worker 的数据。它可以是各种数据类型,包括二进制数据。

接着,主线程通过worker.onmessage指定监听函数,接收子线程发回来的消息。

worker.onmessage = function (event) { console.log('Received message ' + event.data); doSomething(); } function doSomething() { // 执行任务 worker.postMessage('Work done!'); } 复制代码

上面代码中,事件对象的data属性可以获取 Worker 发来的数据。

Worker 完成任务以后,主线程就可以把它关掉。

worker.terminate(); 复制代码 2.2、Worker线程

Worker 线程内部需要有一个监听函数,监听message事件。

self.addEventListener('message', function (e) { self.postMessage('You said: ' + e.data); }, false); 复制代码

上面代码中,self代表子线程自身,即子线程的全局对象。因此,等同于下面两种写法。

// 写法一 this.addEventListener('message', function (e) { this.postMessage('You said: ' + e.data); }, false); // 写法二 addEventListener('message', function (e) { postMessage('You said: ' + e.data); }, false); 复制代码

除了使用self.addEventListener()指定监听函数,也可以使用self.onmessage指定。监听函数的参数是一个事件对象,它的data属性包含主线程发来的数据。self.postMessage()方法用来向主线程发送消息,一般使用self.onmessage较多

根据主线程发来的数据,Worker 线程可以调用不同的方法,下面是一个例子。

self.addEventListener('message', function (e) { var data = e.data; switch (data.cmd) { case 'start': self.postMessage('WORKER STARTED: ' + data.msg); break; case 'stop': self.postMessage('WORKER STOPPED: ' + data.msg); self.close(); // Terminates the worker. break; default: self.postMessage('Unknown command: ' + data.msg); }; }, false); 复制代码

上面代码中,self.close()用于在 Worker 内部关闭自身。

2.3 Worker 加载脚本

Worker 内部如果要加载其他脚本,有一个专门的方法importScripts(),但是不能加载外部文件,如果要加载外部文件,只能将外部文件当作脚本放进文件内部再通过importScripts()引入

importScripts('script1.js'); 复制代码

该方法可以同时加载多个脚本。

importScripts('script1.js', 'script2.js'); 复制代码 2.4 错误处理

主线程可以监听 Worker 是否发生错误。如果发生错误,Worker 会触发主线程的error事件。

worker.onerror(function (event) { console.log([ 'ERROR: Line ', e.lineno, ' in ', e.filename, ': ', e.message ].join('')); }); // 或者 worker.addEventListener('error', function (event) { // ... }); 复制代码

Worker 内部也可以监听error事件。

2.5 关闭 Worker

使用完毕,为了节省系统资源,必须关闭 Worker。

// 主线程 worker.terminate(); // Worker 线程 self.close(); 复制代码 三、数据通信

前面说过,主线程与 Worker 之间的通信内容,可以是文本,也可以是对象。需要注意的是,这种通信是拷贝关系,即是传值而不是传址,Worker 对通信内容的修改,不会影响到主线程。事实上,浏览器内部的运行机制是,先将通信内容串行化,然后把串行化后的字符串发给 Worker,后者再将它还原。

主线程与 Worker 之间也可以交换二进制数据,比如 File、Blob、ArrayBuffer 等类型,也可以在线程之间发送。下面是一个例子。

// 主线程 var uInt8Array = new Uint8Array(new ArrayBuffer(10)); for (var i = 0; i < uInt8Array.length; ++i) { uInt8Array[i] = i * 2; // [0, 2, 4, 6, 8,...] } worker.postMessage(uInt8Array); // Worker 线程 self.onmessage = function (e) { var uInt8Array = e.data; postMessage('Inside worker.js: uInt8Array.toString() = ' + uInt8Array.toString()); postMessage('Inside worker.js: uInt8Array.byteLength = ' + uInt8Array.byteLength); }; 复制代码

但是,拷贝方式发送二进制数据,会造成性能问题。比如,主线程向 Worker 发送一个 500MB 文件,默认情况下浏览器会生成一个原文件的拷贝。为了解决这个问题,JavaScript 允许主线程把二进制数据直接转移给子线程,但是一旦转移,主线程就无法再使用这些二进制数据了,这是为了防止出现多个线程同时修改数据的麻烦局面。这种转移数据的方法,叫做Transferable Objects。这使得主线程可以快速把数据交给 Worker,对于影像处理、声音处理、3D 运算等就非常方便了,不会产生性能负担。

如果要直接转移数据的控制权,就要使用下面的写法。

// Transferable Objects 格式 worker.postMessage(arrayBuffer, [arrayBuffer]); // 例子 var ab = new ArrayBuffer(1); worker.postMessage(ab, [ab]); 复制代码 四、同页面的 Web Worker

通常情况下,Worker 载入的是一个单独的 JavaScript 脚本文件,但是也可以载入与主线程在同一个网页的代码。

addEventListener('message', function () { postMessage('some message'); }, false); 复制代码

上面是一段嵌入网页的脚本,注意必须指定标签的type属性是一个浏览器不认识的值,上例是app/worker。

然后,读取这一段嵌入页面的脚本,用 Worker 来处理。

var blob = new Blob([document.querySelector('#worker').textContent]); var url = window.URL.createObjectURL(blob); var worker = new Worker(url); worker.onmessage = function (e) { // e.data === 'some message' }; 复制代码

上面代码中,先将嵌入网页的脚本代码,转成一个二进制对象,然后为这个二进制对象生成 URL,再让 Worker 加载这个 URL。这样就做到了,主线程和 Worker 的代码都在同一个网页上面。

五、API 5.1 主线程

浏览器原生提供Worker()构造函数,用来供主线程生成 Worker 线程。

var myWorker = new Worker(jsUrl, options); 复制代码

Worker()构造函数,可以接受两个参数。第一个参数是脚本的网址(必须遵守同源政策),该参数是必需的,且只能加载 JS 脚本,否则会报错。第二个参数是配置对象,该对象可选。它的一个作用就是指定 Worker 的名称,用来区分多个 Worker 线程。

// 主线程 var myWorker = new Worker('worker.js', { name : 'myWorker' }); // Worker 线程 self.name // myWorker 复制代码

Worker()构造函数返回一个 Worker 线程对象,用来供主线程操作 Worker。Worker 线程对象的属性和方法如下。

Worker.onerror:指定 error 事件的监听函数。 Worker.onmessage:指定 message 事件的监听函数,发送过来的数据在Event.data属性中。 Worker.onmessageerror:指定 messageerror 事件的监听函数。发送的数据无法序列化成字符串时,会触发这个事件。 Worker.postMessage():向 Worker 线程发送消息。 Worker.terminate():立即终止 Worker 线程。 5.2 Worker 线程

Web Worker 有自己的全局对象,不是主线程的window,而是一个专门为 Worker 定制的全局对象。因此定义在window上面的对象和方法不是全部都可以使用。

Worker 线程有一些自己的全局属性和方法。

self.name: Worker 的名字。该属性只读,由构造函数指定。 self.onmessage:指定message事件的监听函数。 self.onmessageerror:指定 messageerror 事件的监听函数。发送的数据无法序列化成字符串时,会触发这个事件。 self.close():关闭 Worker 线程。 self.postMessage():向产生这个 Worker 线程发送消息。 self.importScripts():加载 JS 脚本。 6、通过JS方式引入worker

vue cli3提供了vue-cli-plugin-worker插件来处理Web Worker文件。在使用该插件之后,你可以在Vue组件中通过import语句来引入.worker.js文件

import MyWorker from "./myWorker.js" const worker = new MyWorker(); worker.postMessage('Hello, worker!'); 复制代码

也可以使用./index?worker.js,因为文件路径后加上?worker来告诉webpack将这个文件作为一个web worker加载

import MyWorker from './myWorker?worker'; const worker = new MyWorker(); worker.postMessage('Hello, worker!'); 复制代码

区别点:这种方式引入的WebWorker也会有DOM限制,但是不会有同源限制,可以加载外部的文件,但是不能使用importScripts这种API

7、在webwork中引入静态文件

通过js方式引入worker缺点就是没有importScripts的API,我在使用draco压缩模型时,需要引入DracoEncoderModule到self中当作全局变量使用,话不多说上代码

// test.vue import compressModelWorker from './compressModel?worker' const worker = new compressModelWorker() // file是input的change文件上传事件的e.target.files[0]文件格式 worker.postMessage({ file }) // compressModel.js self.addEventListener( 'message', async (e) => { // fetch的底层就是XMLHttpRequest封装的 // const response = await fetch('/libs/draco/draco_encoder.js') // const text = await response.text() const test = await getFileFromUrl('/libs/draco/draco_encoder.js') const moduleFunction = new Function(`${text}\n return DracoEncoderModule;`) const DracoEncoderModule = moduleFunction() self.DracoEncoderModule = DracoEncoderModule const file = e.data.file const id = e.data.id const mark = e.data.mark self.postMessage({ data }) }, false ) function getFileFromUrl(url) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest() xhr.open('GET', url, true) xhr.responseType = 'arraybuffer' xhr.onload = () => { if (xhr.status === 200) { resolve(xhr.response) } else { reject(xhr.statusText) } } xhr.onerror = () => reject('URL解析错误') xhr.send() }) } 复制代码 8、XMLHttpRequest 介绍

使用 XMLHttpRequest(XHR)对象可以与服务器交互。您可以从URL获取数据,而无需让整个的页面刷新。这允许网页在不影响用户的操作的情况下更新页面的局部内容。XMLHttpRequest 在 AJAX 编程中被大量使用。 发送一个 HTTP 请求,需要创建一个 XMLHttpRequest 对象,打开一个 URL,最后发送请求。当所有这些事务完成后,该对象将会包含一些诸如响应主体或 HTTP status 的有用信息,XMLHttpRequest 可以用于获取任何类型的数据,而不仅仅是 XML。它甚至支持 HTTP 以外的协议(包括 file:// 和 FTP),尽管可能受到更多出于安全等原因的限制

8.1、 构造函数

XMLHttpRequest()

该构造函数用于初始化一个 XMLHttpRequest 实例对象。在调用下列任何其他方法之前,必须先调用该构造函数,或通过其他方式,得到一个实例对象。

8.2、 属性

此接口继承了 XMLHttpRequestEventTarget 和 EventTarget 的属性。

XMLHttpRequest.onreadystatechange

当 readyState 属性发生变化时,调用的事件处理器。

XMLHttpRequest.readyState 只读

返回 一个无符号短整型(unsigned short)数字,代表请求的状态码。

XMLHttpRequest.response 只读

返回一个 ArrayBuffer、Blob、Document,或 DOMString,具体是哪种类型取决于 XMLHttpRequest.responseType 的值。其中包含整个响应实体(response entity body)。

XMLHttpRequest.responseText 只读

返回一个 DOMString,该 DOMString 包含对请求的响应,如果请求未成功或尚未发送,则返回 null。

XMLHttpRequest.responseType

一个用于定义响应类型的枚举值(enumerated value)。

XMLHttpRequest.responseURL 只读

返回经过序列化(serialized)的响应 URL,如果该 URL 为空,则返回空字符串。

XMLHttpRequest.responseXML 只读

返回一个 Document,其中包含该请求的响应,如果请求未成功、尚未发送或是不能被解析为 XML 或 HTML,则返回 null。

XMLHttpRequest.status 只读

返回一个无符号短整型(unsigned short)数字,代表请求的响应状态。

XMLHttpRequest.statusText 只读



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3