用dw可以做网站吗,镇海官方网站建设,1个百度指数代表多少搜索,公司官方网站建设申请简介
以前我们总说#xff0c;JS 是单线程没有多线程#xff0c;当 JS 在页面中运行长耗时同步任务的时候就会导致页面假死影响用户体验#xff0c;从而需要设置把任务放在任务队列中#xff1b;执行任务队列中的任务也并非多线程进行的#xff0c;然而现在 HTML5 提供了…简介
以前我们总说JS 是单线程没有多线程当 JS 在页面中运行长耗时同步任务的时候就会导致页面假死影响用户体验从而需要设置把任务放在任务队列中执行任务队列中的任务也并非多线程进行的然而现在 HTML5 提供了我们前端开发这样的能力 - Web Workers API我们一起来看一看 Web Worker 是什么怎么去使用它在实际生产中如何去用它来进行产出。
概述
Web Workers 使得一个 Web 应用程序可以在与主执行线程分离的后台线程中运行一个脚本操作。这样做的好处是可以在一个单独的线程中执行费时的处理任务从而允许主通常是 UI线程运行而不被阻塞。
它的作用就是给 JS 创造多线程运行环境允许主线程创建 worker 线程分配任务给后者主线程运行的同时 worker 线程也在运行相互不干扰在 worker 线程运行结束后把结果返回给主线程。这样做的好处是主线程可以把计算密集型或高延迟的任务交给 worker 线程执行这样主线程就会变得轻松不会被阻塞或拖慢。这并不意味着 JS 语言本身支持了多线程能力而是浏览器作为宿主环境提供了 JS 一个多线程运行的环境。
不过因为 worker 一旦新建就会一直运行不会被主线程的活动打断这样有利于随时响应主线程的通性但是也会造成资源的浪费所以不应过度使用用完注意关闭。或者说如果 worker 无实例引用该 worker 空闲后立即会被关闭如果 worker 实列引用不为 0该 worker 空闲也不会被关闭。
兼容性 注意事项
worker 线程的使用有一些注意点
同源限制 worker 线程执行的脚本文件必须和主线程的脚本文件同源这是当然的了总不能允许 worker 线程到别人电脑上到处读文件吧文件限制 为了安全worker 线程无法读取本地文件它所加载的脚本必须来自网络且需要与主线程的脚本同源DOM 操作限制 worker 线程在与主线程的 window 不同的另一个全局上下文中运行其中无法读取主线程所在网页的 DOM 对象也不能获取 document、window等对象但是可以获取navigator、location(只读)、XMLHttpRequest、setTimeout族等浏览器API通信限制 worker 线程与主线程不在同一个上下文不能直接通信需要通过postMessage方法来通信 脚本限制 worker 线程不能执行alert、confirm但可以使用 XMLHttpRequest 对象发出 ajax 请求
示例
在主线程中生成 Worker 线程很容易
var myWorker new Worker(jsUrl, options)Worker() 构造函数第一个参数是脚本的网址必须遵守同源政策该参数是必需的且只能加载 JS 脚本否则报错。第二个参数是配置对象该对象可选。它的一个作用就是指定 Worker 的名称用来区分多个 Worker 线程。
// 主线程var myWorker new Worker(worker.js, { name : myWorker });// Worker 线程
self.name // myWorker关于 api 什么的直接上例子大概就能明白了首先是 worker 线程的 js 文件
workerThread1.js 文件中
关于 api 什么的直接上例子大概就能明白了首先是 worker 线程的 js 文件// workerThread1.jslet i 1function simpleCount() {iself.postMessage(i)setTimeout(simpleCount, 1000)
}simpleCount()self.onmessage ev {postMessage(ev.data 呵呵~)
}在 HTML 文件中的 body 中
在 HTML 文件中的 body 中!--主线程HTML文件的body标签中--divWorker 输出内容span idapp/spaninput typetext title idmsgbutton onclicksendMessage()发送/buttonbutton onclickstopWorker()stop!/button
/divscript typetext/javascriptif (typeof(Worker) undefined) // 使用Worker前检查一下浏览器是否支持document.writeln( Sorry! No Web Worker support.. )else {window.w new Worker(workerThread1.js)window.w.onmessage ev {document.getElementById(app).innerHTML ev.data}window.w.onerror err {w.terminate()console.log(error.filename, error.lineno, error.message) // 发生错误的文件名、行号、错误内容}function sendMessage() {const msg document.getElementById(msg)window.w.postMessage(msg.value)}function stopWorker() {window.w.terminate()}}
/scriptapi
主线程中的apiworker表示是 Worker 的实例
worker.postMessage: 主线程往 worker 线程发消息消息可以是任意类型数据包括二进制数据worker.terminate: 主线程关闭 worker 线程worker.onmessage: 指定 worker 线程发消息时的回调也可以通过worker.addEventListener(‘message’,cb)的方式worker.onerror: 指定 worker 线程发生错误时的回调也可以 worker.addEventListener(‘error’,cb)
Worker 线程中全局对象为 self代表子线程自身这时 this指向self其上有一些 api
self.postMessage: worker 线程往主线程发消息消息可以是任意类型数据包括二进制数据self.close: worker 线程关闭自己self.onmessage: 指定主线程发 worker 线程消息时的回调也可以self.addEventListener(‘message’,cb)self.onerror: 指定 worker 线程发生错误时的回调也可以 self.addEventListener(‘error’,cb)
注意w.postMessage(aMessage, transferList) 方法接受两个参数aMessage 是可以传递任何类型数据的包括对象这种通信是拷贝关系即是传值而不是传址Worker 对通信内容的修改不会影响到主线程。事实上浏览器内部的运行机制是先将通信内容串行化然后把串行化后的字符串发给 Worker后者再将它还原。一个可选的 Transferable 对象的数组用于传递所有权。如果一个对象的所有权被转移在发送它的上下文中将变为不可用中止并且只有在它被发送到的 worker 中可用。可转移对象是如 ArrayBufferMessagePort 或 ImageBitmap 的实例对象transferList数组中不可传入 null。
worker 线程中加载脚本的 api
importScripts(script1.js) // 加载单个脚本
importScripts(script1.js, script2.js) // 加载多个脚本使用场景
个人觉得Web Worker 我们可以当做计算器来用需要用的时候掏出来摁一摁不用的时候一定要收起来。
加密数据 有些加解密的算法比较复杂或者在加解密很多数据的时候这会非常耗费计算资源导致 UI 线程无响应因此这是使用 Web Worker 的好时机使用 Worker 线程可以让用户更加无缝的操作 UI。
预取数据 有时候为了提升数据加载速度可以提前使用 Worker 线程获取数据因为 Worker 线程是可以是用 XMLHttpRequest 的。
预渲染 在某些渲染场景下比如渲染复杂的 canvas 的时候需要计算的效果比如反射、折射、光影、材料等这些计算的逻辑可以使用 Worker 线程来执行也可以使用多个 Worker 线。
复杂数据处理场景 某些检索、排序、过滤、分析会非常耗费时间这时可以使用 Web Worker 来进行不占用主线程。
预加载图片 有时候一个页面有很多图片或者有几个很大的图片的时候如果业务限制不考虑懒加载也可以使用 Web Worker 来加载图片可以参考一下这篇文章的探索这篇文章的探索这里简单提要一下。
// 主线程
let w new Worker(js/workers.js);
w.onmessage function (event) {var img document.createElement(img);img.src window.URL.createObjectURL(event.data);document.querySelector(#result).appendChild(img)
}// worker线程
let arr [...好多图片路径];
for (let i 0, len arr.length; i len; i) {let req new XMLHttpRequest();req.open(GET, arr[i], true);req.responseType blob;req.setRequestHeader(client_type, DESKTOP_WEB);req.onreadystatechange () {if (req.readyState 4) {postMessage(req.response);}}req.send(null);
}在实战的时候注意
虽然使用 worker 线程不会占用主线程但是启动 worker 会比较耗费资源主线程中使用 XMLHttpRequest 在请求过程中浏览器另开了一个异步 http 请求线程但是交互过程中还是要消耗主线程资源
在 Webpack 项目里面使用 Web Worker 请参照怎么在 ES6Webpack 下使用 Web Worker
参考文章
mdn
前端 Web Workers 到底是什么
Web Worker在项目中的妙用