HTML5之彩票平台搭建多线程(Web Worker)
提到 HTML5 总是让人津津乐道,太多的特性和有趣的 API 让人耳目一新。但是很多童鞋还停留在语义化的阶段,忽视了 HTML5 的强劲之处。
这节我们来探讨一下多线程 Web-Worker。
一、明确 JavaScript 是单线程
JavaScript 语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。
听起来有些匪夷所思,为什么不设计成多线程提高效率呢?我们可以假设一种场景:
假定 JavaScript
同时有两个线程,一个线程在某个 DOM
节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
作为浏览器脚本语言, JavaScript
的主要用途是与用户互动,以及操作 DOM
。
这决定了它只能是单线程,否则会带来很复杂的同步问题。为了避免复杂性,从一诞生, JavaScript
就是单线程,这已经成了这门语言的核心特征,估计短期内很难改变。
二、新曙光:Web Worker
单线程始终是一个痛点,为了利用多核 CPU
的计算能力, HTML5
提出 Web Worker
标准,允许 JavaScript
脚本创建多个线程。但是子线程完全受主线程控制,且不得操作 DOM
。
所以,这个新标准并没有改变 JavaScript
单线程的本质。
Web Workers
是现代浏览器提供的一个 JavaScript
多线程解决方案,我们可以找到很多使用场景:
1.我们可以用 Web Worker
做一些大计算量的操作;
2.可以实现轮询,改变某些状态;
3.页头消息状态更新,比如页头的消息个数通知;
4.高频用户交互,拼写检查,譬如:根据用户的输入习惯、历史记录以及缓存等信息来协助用户完成输入的纠错、校正功能等
5.加密:加密有时候会非常地耗时,特别是如果当你需要经常加密很多数据的时候(比如,发往服务器前加密数据)。
6.预取数据:为了优化网站或者网络应用及提升数据加载时间,你可以使用 Workers
来提前加载部分数据以备不时之需。
加密是一个使用 Web Worker
的绝佳场景,因为它并不需要访问 DOM
或者利用其它魔法,它只是纯粹使用算法进行计算而已。随着大众对个人敏感数据的日益重视,信息安全和加密也成为重中之重。这可以从近期的 12306 用户数据泄露事件中体现出来。
一旦在 Worker 进行计算,它对于用户来说是无缝地且不会影响到用户体验。
三、兼容性
四、基本概念
1.首先记得去判断是否支持
1 2 3 |
|
2.创建一个新的 worker
很简单
1 |
|
postMessage() 方法和 onmessage 事件处理函数是 Workers 的黑魔法。
3. postMessage
用来发送消息,而 onmessage
用来监听消息
1 2 3 4 5 |
|
在主线程中使用时, onmessage
和 postMessage()
必须挂在 worker
对象上,而在 worker
中使用时不用这样做。原因是,在 worker
内部, worker
是有效的全局作用域。
4.异常处理:
1 2 3 4 |
|
5.终止 worker
1 |
|
worker
线程会被立即杀死,不会有任何机会让它完成自己的操作或清理工作。
6.在 worker
线程中, workers
也可以调用自己的 close
方法进行关闭:
1 |
|
五、快速开始
为了快速掌握,我们来做一个小例子:项目结构如下
1 2 3 4 |
|
Html
1 2 3 4 5 6 7 8 9 10 |
|
main.js
1 2 3 4 5 6 7 |
|
Work.js
1 2 3 4 5 6 7 |
|
代码很简单,主线程发送:「写的真好!」
web worker 收到消息,发现内容中含有「好」字,回传给主线程:「谢谢支持」
六、局限性
1.在 worker
内,不能直接操作 DOM
节点,也不能使用 window
对象的默认方法和属性。然而我们可以使用大量 window
对象之下的东西,包括 WebSockets
, IndexedDB
以及 FireFox OS
专用的 Data Store API
等数据存储机制。
这里举个例子,我们修改 main.js
:
1 2 3 4 5 6 7 8 9 10 11 |
|
再来修改 work.js
1 2 3 4 5 6 7 8 |
|
这时候运行就会报出:
这是因为: 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
有如下头部声明:
1 |
|
这个声明有一部分作用在于,禁止它内部包含的脚本代码使用 eval()
方法。然而,如果脚本代码创建了一个 worker
,在 worker
上下文中执行的代码却是可以使用 eval()
的。
为了给 worker 指定 CSP,必须为发送 worker 代码的请求本身加上一个 CSP。
有一个例外情况,即 worker
脚本的源如果是一个全局性的唯一的标识符(例如,它的 URL
指定了数据模式或者 blob
), worker
则会继承创建它的 document
或者 worker
的 CSP
。
七、扩展:WorkerGlobalScope
关于 ,我们可以在 MDN
上面找到文档:
1. self
:
我们可以使用 WorkerGlobalScope
的 self
属性来获取这个对象本身的引用。
2. location
:
location
属性返回当线程被创建出来的时候与之关联的 WorkerLocation
对象,它表示用于初始化这个工作线程的脚步资源的绝对 URL
,即使页面被多次重定向后,这个 URL
资源位置也不会改变。
3. close
:
关闭当前线程,与 terminate
作用类似。
4. caches
:
当前上下文得 CacheStorage
,确保离线可用,同时可以自定义请求的响应。
5. console
:
支持 console
语法。
6. importScripts
我们可以通过 importScripts()
方法通过 url
在 worker
中加载库函数。
7. XMLHttpRequest
有了它,才能发出 Ajax
请求。
8.可以使用:
- setTimeout/setInterval
- addEventListener/postMessage
还有很多 API
可以使用,这里就不一一举例了。
八、异常处理
当 worker
出现运行中错误时,它的 onerror
事件处理函数会被调用。它会收到一个扩展了 ErrorEvent
接口的名为 error
的事件。该事件不会冒泡并且可以被取消。
为了防止触发默认动作,worker 可以调用错误事件的 preventDefault() 方法。
错误事件我们常用如下这三个关键信息:
- Message:可读性良好的错误消息;
- Filename:发生错误的脚本文件名;
- Lineno:发生错误时所在脚本文件的行号;
1 2 3 4 |
|
- 使用mitmproxy嗅探双向认证ssl链接——嗅探AWS IoT SDK的mqtts
- Django中ORM介绍和字段及其参数
- 几个实现分页的方法
- 如何识别IDA反汇编中动态链接库中的函数
- Kali Linux安装TL-WN821N USB无线网卡驱动(make失败)
- Cookie、Session登陆验证相关介绍和用法
- 题型分析
- .NET CORE 框架ABP的代码生成器(ABP Code Power Tools )使用说明文档
- Lua编写wireshark插件初探——解析Websocket上的MQTT协议
- 在Ubuntu 16.04环境下安装Docker-CE(附视频教程)
- 修改HTML5 input placeholder 颜色及修改失效的解决办法
- 设置同样字体大小,chrome浏览器有时字体偏大的解决办法(转)
- 手机端调用系统相册并上传图片
- select自定义小三角样式
- HTML 教程
- HTML 简介
- html div 标签介绍
- html span 标签介绍
- html a 超链接标签
- HTML Br换行标签介绍
- HTML P段落标签介绍
- HTML br与p标签区别
- Html H 标题标签
- html px em pt长度单位
- HTML form 标签
- HTML radio 单选框
- HTML B 加粗标签
- HTML strong加粗粗体标签
- HTML em 强调标签
- HTML i 斜体标签
- HTML u下划线标签
- HTML s 删除线标签
- Html img 图片标签
- Html上标注sup与下标注sub标签
- HTML nobr 禁止换行标签
- HTML hr 水平线标签
- HTML label 标签
- HTML input 标签
- HTML textarea 标签
- HTML select下拉列表标签
- HTML checkbox 多选框
- HTML font color 标签
- HTML iframe 框架标签
- HTML Table 表格
- HTML dl dt dd 标签
- HTML ol li有序列表标签
- HTML ul li 无序列表标签
- HTML 注释
- CSS 教程
- CSS 简介
- CSS 语法
- CSS Id 和 Class选择器
- CSS 样式的创建
- CSS background 背景介绍
- CSS 文本样式
- CSS font 字体
- CSS A 链接
- CSS ul ol列表样式
- CSS TABLE 样式
- CSS 框模型
- CSS border 边框
- CSS Outlines 轮廓
- CSS 外边距 Margin
- CSS Padding 内边距
- CSS 分组和嵌套选择器
- CSS 尺寸 (Dimension)
- CSS Display 属性
- CSS Position 定位
- CSS Float 浮动
- CSS 水平对齐(Horizontal Align)
- CSS 组合选择符
- CSS 伪类
- CSS 伪元素
- CSS 导航栏
- CSS 下拉菜单
- CSS 图片廊
- CSS 图像透明/不透明
- CSS sprite 图像拼合技术
- CSS 媒体类型
- CSS 属性选择器
- CSS 实例
- springboot开发之配置自定义的错误界面和错误信息
- springboot开发之删除员工
- LeetCode | 1.两数之和
- springboot开发之配置嵌入式Servlet容器两种方式
- jvaa之初始化块
- java之匿名内部类
- springboot配置之获取配置文件中属性的第二种方法(@Value)不同于@ConfigurationProperties
- mybatis动态sql之内置参数_parameter和_databaseId
- Redis | Redis 字符串相关命令
- java之抽象类
- springboot配置之yaml
- properties和yaml配置文件
- java之模板方法设计模式
- java之接口
- PHP 代码混淆处理思路