Web Worker && postMessage && onMessage 使用教程
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Web Worker && postMessage && onMessage 使用教程相关的知识,希望对你有一定的参考价值。
参考技术A **转自博客原文连接: https://tong-h.github.io/2019/04/21/webworker/**
最近使用 iframe 的时候想要获取 iframe 文档信息的时候遇到了跨域问题,最后使用 postmessage 做父子页面通信解决需求也顺便学习了下 webworker 的使用
webWoker 使用依赖 postMessage() 和 onMessage(), 所以先说这两个吧
message: 发送的数据,不限类型,因为他自己会序列化
targetOrigin:通过窗口的origin属性指定哪些窗口能接收到消息事件,其值可以是字符串"*"(表示无限制)或者一个URI
transfer:可选参数;一个 Transferable 对象([什么是Transferable[( https://developer.mozilla.org/zh-CN/docs/Web/API/Transferable) ),和message 同时传递的,对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权
data:接收的数据对象,对应 postMessage 的 message 参数
origin:消息发送方窗口的 origin,字符串由 协议、“://“、域名、“ : 端口号”拼接而成
source:对发送消息的窗口对象的引用
在使用 worker 的 js文件里
在 worker.js文件
如果你现在没有条件加载网络上的文件,可以使用 URL.createObjectURL 方法建立缓存 URL
可以试着运行一下面两个页面感受一下
可以运行一下这个页面,一个普通的 for 循环,因为数字太大运行时会有明显的卡顿
这个可以使用 URL.createObjectURL 方法建立缓存 URL
postMessage:MDN https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage
webworker:MDN https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Workers_API/Using_web_workers
阮一峰: http://www.ruanyifeng.com/blog/2018/07/web-worker.html
HTML5( Web Worker ) & 微信小程序多线程
随着互联网的发展,技术也在不断的更新,2014年10月29日
万维网联盟发布HTML5语言标准,HTML5推出了很多API例如Geolocation(地理定位)
,Storage(本地存储)
、Cache Manifest(应用程序缓存)
、Server-Sent(自动获取来自服务器的更新)
、WebSocket(及时通讯)
和indexedDB(本地数据库)
,还有一个就是接下来要说的Web Worker(多线程)
。
学习JavaScript
的人都知道JavaScript
语言不如java
、C#
等,其他强类型语言使用的是多线程处理程序,JavaScript
使用单线程处理程序。
JavaScript为什么不适用多线程
JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
进行&线程
进程
进程是指在操作系统中正在运行的一个应用程序
线程
线程是指进程内独立执行某个任务的一个单元。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈)。
什么是Web Worker
web worker 是运行在后台的 JavaScript,独立于其他脚本,不会影响页面的性能。您可以继续做任何愿意做的事情:点击、选取内容等等,而此时 web worker 在后台运行。
一般来说Javascript
和页面的UI会共用一个线程,所以当点击一个按钮开始运行Javascript
后,在这段代码运行完毕之前,页面是无法响应用户操作的,换句话来说就是被“冻结
”了,即使是异步的也会被冻结
。如下面这段代码。
window.onload = () => {
alert(1)
setInterval(() => {
console.log(1)
},500)
}
上面这段代码在页面加载完成以后,先执行alert
然而,alert
页面进入了无法相应的状态,换句话来说,下面的代码就被冻结了,只有把alert
确定以后才会执行下面的定时器。
而这段代码可以交给Web Worker
在后台运行,那么页面在Javascript
运行期间依然可以响应用户操作。后台会启动一个worker
线程来执行这段代码,用户可以创建多个worker
线程。
Web Worker提供了什么
加载一个
JavaScript
文件,进行大量的复杂计算,而不挂起主进程,并通过postMessage
和onMessage
进行通信。可以再
Worker
中通过importScript()
方法加载JavaScrip
脚本可以使用
setTimeOut()
、setInterVal()
、clearTimeout()
、clearInterVal()
等。可以使用
XMLHttpRequest
进行请求。可以访问
navigator
的部分属性可以使用
JavaScript
核心对象
Web Worker限制
不能跨域加载
JavaScript
文件。Worker
内代码不能访问DOM。各个浏览器对
Worker
的实现还没有完全完善,不是每个浏览器都能支持这一新特性。使用
Web Workers
加载数据没有JSON
和Ajax
加载数据高效。
Web Worker主要成员
在使用Web Worker之前,应该先熟悉一下线程中可用的变量,函数和类。在线程中调用JavaScript函数中的所有,可使用类和函数如下:
self:
self
关键值用来表示本线程范围内的作用域。postMessage:向创建线程的原窗口发送消息。
navigator:与
window.navigator
对象类似,具有appName
,platform
、userAgent
和appVersion
属性。他们可以用来识别浏览器的标识符。sessionStorage/localStorage:在线程中可以使用
web Storage
。XMLHttpRequest:在线程中可以处理
Ajax
请求。setTimeOut/setInterVal:在线程中可以实现定时处理。
close:结束本线程。
eval()/isNaN/escape()等:可以使用所有
JavaScript
核心函数。object:可以创建和使用本地对象。
WebSockets:可以使用
Web Sockets
API向服务器发送和接收消息。
浏览器兼容性
浏览器 | 说明 |
---|---|
IE | 不支持 |
firefox | 3.5以及以上的版本 |
Opera | 10.6及以上的版本 |
Chrome | 3.0及以上的版本 |
Safari | 4.0及以上的版本 |
# 兼容性检测
let isWorker = () => {
let flag = false;
if(typeof(Worker)!=="undefined"){
flag = true;
}
return flag;
}
Web Worker简单应用
简单看一下代码是怎么实现的。需要注意的是一定要在服务器环境下才能正常使用Web Worker。
index.html
<html>
<head>
<script type="text/javascript">
var worker = new Worker('worker.js');
var obj = {"first":1, "second":2};
worker.postMessage(obj);
worker.onmessage = function (event) {
console.log(event.data);
}
function postMsg(){
if (worker)
worker.postMessaage(obj);
}
</script>
</head>
<body>
<button onclick="postMsg()">post</button>
</body>
</html>
worker.js
onmessage = function (event)
{
var data = event.data;
var first=data.first;
var second=data.second;
handleTask(first,second);
};
function handleTask(a, b)
{
var out = a + b;
postMessage("Worker Done! out = " + out);
}
运行代码:点击查看案例
Web Worker运行流程
执行到"var worker = new Worker('worker.js')“时,在内核中构造WebCore::JSWorker对象(JSBbindings层)以及对应的WebCore::Worker对象(WebCore模块);
执行worker.postMessage(),向worker线程发送JSON格式化的消息数据; 因为这个时候,worker线程还没有创建,所以消息数据放在一个临时消息队列中;
worker.js异步加载完成后,创建并启动worker线程,并将临时消息队列中的消息数据copy到woker对应的WorkerRunLoop的消息队列中;
worker线程创建完成后,开始处理WorkerRunLoop的消息队列中所保存的消息;
woker线程发送消息到主线程;
主线程收到worker线程发送的消息,执行onMessage();
Web Worker案例
生成200个100以内随机数,筛选出能被3整除的,并展示到页面。
index.html
let $ = (id) => {
return document.getElementById(id);
}
window.onload = () => {
let arr = [];
for(let i=0;i<200;i++){
arr.push(Number.parseInt(Math.random()*100));
}
let worker = new Worker("/www/worker/worker2.js");
worker.postMessage(JSON.stringify(arr));
worker.onerror = (err) => {
console.log(err);
}
worker.onmessage = (event) => {
let arr = event.data;
arr.map((el,i) => {
let li = document.createElement("li");
li.innerHTML = el;
$("ul").appendChild(li);
})
}
}
worker.js
onmessage = (event) => {
let arr = JSON.parse(event.data);
let a = arr.filter((el,i) => {
return el%3 === 0;
})
postMessage(a);
}
运行代码:点击查看案例
共享线程
共享线程是为了避免线程的重复创建和销毁过程,降低了系统性能的消耗,共享线程SharedWorker
可以同时有多个页面的线程链接。
var worker = new SharedWorker("sharedworker.js");
共享线程也使用了message事件监听线程消息,但使用SharedWorker对象的port属性与线程通信如下。
worker.port.onmessage = function(e){
...
}
同时我们也可以使用SharedWorker对象的port属性向共享线程发送消息如下。
worker.port.postMessage("message");
小结
在写这篇文章之前看了很多博客,同样也看了 ++HTML5+CSS3从入门到精通++ 这本书,很多博客都说可以进行线程嵌套,一定要记住,是不能进行线程嵌套的,就是在 worker.js
文件里面再次 new Worker
这样的话会报错。原因是Worker
对象属于window
,所以在线程文件中使用Worker
对象会抛出错误Worker is not defined
。
Web Worker
可以在后台完成复杂的数据计算。这是其最有利的地方。所以一定要合理的使用这一特点。不是任何时候都适用Web Worker
,否则会有些小题大做,给维护带来没有必要的麻烦。
微信小程序多线程
创建一个 Worker
线程,并返回 Worker
实例,目前限制最多只能创建一个 Worker
,创建下一个 Worker
前请调用 Worker.terminate
。
微信小程序的多线程和H5多线程是类似的,唯一的区别就是,小程序多线程处理无需服务器环境即可运行了。
scriptPath 为 worker 的入口文件路径,需填写绝对路径。
app.js
const worker = wx.createWorker('workers/request/index.js');
worker.postMessage({
msg: 'hello worker'
})
worker.onMessage(function (res) {
console.log(res)
})
worker.terminate
worker.js
worker.onMessage(function (res) {
console.log(res.msg)
})
worker.postMessage("线程返回的数据")
总结
当我们创建一个新的worker
时,改代码会运行在一个全新的javascript
的环境中运行,是完全和创建worker
的脚本隔离,这时我们可以把创建新worker
的脚本叫做主线程,而被创建的新的worker
叫做子线程。
但是我们所开启的新的worker也就是子线程,并不支持操作页面的DOM。
HTML5 Web Worker 需要服务器环境才能正常使用,使用线程文件和worker文件必须在同一个域下面。否则无法运行。
这个很重要。
--- End ---
邦邦堂
以上是关于Web Worker && postMessage && onMessage 使用教程的主要内容,如果未能解决你的问题,请参考以下文章
HTML5( Web Worker ) & 微信小程序多线程
断言失败:第 24 行 pos 15:'color != null && color.alpha == 0xFF':不正确