这篇文章主要介绍了HTML5之多线程(Web Worker)的相关资料,写的十分的全面细致,具有一定的参考价值,对此有需要的朋友可以参考学习下。如有不足之处,欢迎批评指正。
提到 HTML5 总是让人津津乐道,太多的特性和有趣的 API 让人耳目一新。但是很多童鞋还停留在语义化的阶段,忽视了 HTML5 的强劲之处。
这节我们来探讨一下多线程 Web-Worker。
一、明确 JavaScript 是单线程
JavaScript 语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。
听起来有些匪夷所思,为什么不设计成多线程提高效率呢?我们可以假设一种场景:
假定 JavaScript 同时有两个线程,一个线程在某个 DOM 节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
作为浏览器脚本语言, JavaScript 的主要用途是与用户互动,以及操作 DOM 。
这决定了它只能是单线程,否则会带来很复杂的同步问题。为了避免复杂性,从一诞生, JavaScript 就是单线程,这已经成了这门语言的核心特征,估计短期内很难改变。
二、新曙光:Web Worker
单线程始终是一个痛点,为了利用多核 CPU 的计算能力, HTML5 提出 Web Worker 标准,允许 JavaScript 脚本创建多个线程。但是子线程完全受主线程控制,且不得操作 DOM 。
所以,这个新标准并没有改变 JavaScript 单线程的本质。
在此我向大家推荐一个前端全栈开发交流圈:619586920 突破技术瓶颈,提升思维能力
Web Workers 是现代浏览器提供的一个 JavaScript 多线程解决方案,我们可以找到很多使用场景:
三、兼容性
四、基本概念
1.首先记得去判断是否支持
if (window.Worker) {
...
}
2.创建一个新的 worker 很简单
const myWorker = new Worker('worker.js');
postMessage() 方法和 onmessage 事件处理函数是 Workers 的黑魔法。
3. postMessage 用来发送消息,而 onmessage 用来监听消息
const worker = new Worker('src/worker.js');
worker.onmessage = e => {
console.log(e.data);
};
worker.postMessage('你好吗!');
在此我向大家推荐一个前端全栈开发交流圈:619586920 突破技术瓶颈,提升思维能力
在主线程中使用时, onmessage 和 postMessage() 必须挂在 worker 对象上,而在 worker 中使用时不用这样做。原因是,在 worker 内部, worker 是有效的全局作用域。
4.异常处理:
worker.onerror = function(error) {
console.log(error.message);
throw error;
};
5.终止 worker
worker.terminate();
worker 线程会被立即杀死,不会有任何机会让它完成自己的操作或清理工作。
6.在 worker 线程中, workers 也可以调用自己的 close 方法进行关闭:
close();
五、快速开始
为了快速掌握,我们来做一个小例子:项目结构如下
├── index.html
└── src
├── main.js
└── worker.js
html
Web Work Demo
Hello Jartto!
main.js
const worker = new Worker('src/worker.js');
worker.onmessage = e => {
const message = e.data;
console.log(`[From Worker]: ${message}`);
document.getElementById('app').innerHTML = message;
};
worker.postMessage('写的真好!');
Work.js
onmessage = e => {
const message = e.data;
console.log(`[From Main]: ${message}`);
if(message.indexOf('好') > -1) {
postMessage('谢谢支持');
}
};在此我向大家推荐一个前端全栈开发交流圈:619586920 突破技术瓶颈,提升思维能力
代码很简单,主线程发送:「写的真好!」
web worker 收到消息,发现内容中含有「好」字,回传给主线程:「谢谢支持」
六、局限性
1.在 worker 内,不能直接操作 DOM 节点,也不能使用 window 对象的默认方法和属性。然而我们可以使用大量 window 对象之下的东西,包括 WebSockets , IndexedDB 以及 FireFox OS 专用的 Data Store API 等数据存储机制。
这里举个例子,我们修改 main.js :
const worker = new Worker('src/worker.js');
worker.onmessage = e => {
const message = e.data;
console.log(`[From Worker]: ${message}`);
document.getElementById('app').innerHTML = message;
};
+ worker.onerror = function(error) {
+ console.log(error);
+ worker.terminate();
+ };
worker.postMessage('写的真好!');
再来修改 work.js
+ alert('jartto');
onmessage = e => {
const message = e.data;
console.log(`[From Main]: ${message}`);
if(message.indexOf('好') > -1) {
postMessage('谢谢支持');
}
};
在此我向大家推荐一个前端全栈开发交流圈:619586920 突破技术瓶颈,提升思维能力
这是因为: worker.js 执行的上下文,与主页面 HTML 执行时的上下文并不相同,最顶层的对象并不是 Window , woker.js 执行的全局上下文,而是 WorkerGlobalScope ,我们具体说明。
2. workers 和主线程间的数据传递通过这样的消息机制进行:双方都使用 postMessage() 方法发送各自的消息,使用 onmessage 事件处理函数来响应消息(消息被包含在 Message 事件的 data 属性中)。
这个过程中数据并不是被共享而是被复制。
3.同源限制
分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。
4.文件限制
Worker 线程无法读取本地文件,即不能打开本机的文件系统 (file://) ,它所加载的脚本,必须来自服务器。
5.不允许本地文件
Uncaught SecurityError: Failed to create a worker:
script at ‘(path)/worker.js’
cannot be accessed from origin ‘null’.
Chrome doesn’t let you load web workers when running scripts from a local file.
那如何解决呢?我们可以启动一个本地服务器,建议使用 http-server ,简单易用。
6.内容安全策略
有别于创建它的 document 对象, worker 有它自己的执行上下文。因此普遍来说, worker 并不受限于创建它的 document (或者父级 worker )的内容安全策略。
我们来举个例子,假设一个 document 有如下头部声明:
Content-Security-Policy: script-src 'self'
这个声明有一部分作用在于,禁止它内部包含的脚本代码使用 eval() 方法。然而,如果脚本代码创建了一个 worker ,在 worker 上下文中执行的代码却是可以使用 eval() 的。
在此我向大家推荐一个前端全栈开发交流圈:619586920 突破技术瓶颈,提升思维能力
为了给 worker 指定 CSP,必须为发送 worker 代码的请求本身加上一个 CSP。
有一个例外情况,即 worker 脚本的源如果是一个全局性的唯一的标识符(例如,它的 URL 指定了数据模式或者 blob ), worker 则会继承创建它的 document 或者 worker 的 CSP 。
七、扩展:WorkerGlobalScope
关于 ,我们可以在 MDN 上面找到文档:
八、异常处理
当 worker 出现运行中错误时,它的 onerror 事件处理函数会被调用。它会收到一个扩展了 ErrorEvent 接口的名为 error 的事件。该事件不会冒泡并且可以被取消。
为了防止触发默认动作,worker 可以调用错误事件的 preventDefault() 方法。
错误事件我们常用如下这三个关键信息:
Message:可读性良好的错误消息;
Filename:发生错误的脚本文件名;
Lineno:发生错误时所在脚本文件的行号;
worker.onerror = function(error) {
console.log(error.message);
throw error;
};
结语
感谢您的观看,如有不足之处,欢迎批评指正。
#获取资料
本次给大家推荐一个免费的学习群,里面概括移动应用网站开发,css,html,webpack,vue node angular以及面试资源等。
对web开发技术感兴趣的同学,欢迎加入Q群:619586920,不管你是小白还是大牛我都欢迎,还有大牛整理的一套高效率学习路线和教程与您免费分享,同时每天更新视频资料。
最后,祝大家早日学有所成,拿到满意offer,快速升职加薪,走上人生巅峰。