浅谈webWorker
一、webWorker之初体验 |
在"setTimeout那些事儿"中,说到JavaScript是单线程。也就是同一时间只能做同一事情。
也好理解,作为浏览器脚本语言,如果JavaScript不是单线程,那么就有点棘手了。比如,与用户交互或者对DOM进行操作时,在一个线程上修改某个DOM,另外的线程删除DOM,这时浏览器该如何抉择呢?
所以,JavaScript是单线程也是有背景的。
如下:
<!DOCTYPE html>
<head>
<title>singleThread</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<script>
//添加到任务队列中,待同步任务所处的‘执行栈’执行完毕,1秒后执行任务队列中的这个匿名函数
setTimeout(function(){
console.log('come on');
},1000);
//只要不关闭该alert,‘执行栈’就没结束,从而也就不会进入到任务队列中
alert('waiting');
</script>
</body>
</html>
但,HTML5引入了一个工作线程(webWorker)的概念。它允许开发人员编写能够长时间运行而不被用户所中断的后台程序,去执行事务或者逻辑,并同时保证页面对用户的响应。
简而言之,就是允许JavaScript创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。
从而,可以用webWorker来处理一些比较耗时的计算。
如下,主页面:
<!DOCTYPE html>
<head>
<title>worker</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script>
function init(){
//创建一个Worker对象,并向它传递将在新线程中执行的脚本url
var worker = new Worker('worker.js');
//接收worker传递过来的数据
worker.onmessage = function(event){
document.getElementById('result').innerHTML+=event.data+"<br/>" ;
};
};
</script>
</head>
<body onload = "init()">
<div id="result"></div>
</body>
</html>
下面是worker.js的内容:
var i = 0;
function timedCount(){
for(var j = 0, sum = 0; j < 100; j++){
for(var i = 0; i < 100000000; i++){
sum+=i;
};
};
//将得到的sum发送回主线程
postMessage(sum);
};
//将执行timedCount前的时间,通过postMessage发送回主线程
postMessage('Before computing, '+new Date());
timedCount();
//结束timedCount后,将结束时间发送回主线程
postMessage('After computing, ' +new Date());
上面代码执行的流程是:创建的worker对象,并用onmessage方法接收worker.js里面postMessage传递过来的数据(event.data),并将数据追加到div#result中。
所以,执行上面的代码结果如下:
图一
待worker.js中的timedCount方法运算完后,执行postMessage操作,向主线程传数据,得图二。期间,并不影响主线程的运作。
图二
二、webWorker之常用API |
接下来,再来看看关于worker的常用API:
1、postMessage(data)
子线程与主线程之间互相通信使用方法,传递的data为任意值。
//worker = new Worker('url');
//worker.postMessage传递给子线程数据,对象
worker.postMessage({first:1,second:2}); //子线程中也可以使用postMessage,如传递字符串
postMessage(‘test’);
2、terminate()
主线程中终止worker,此后无法再利用其进行消息传递。注意:一旦terminate后,无法重新启用,只能另外创建。
//worker = new Worker('url');
worker.terminate();
如,主页面:
<!DOCTYPE html>
<head>
<title>worker</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script>
function init(){
var worker = new Worker('worker.js');
//每隔100毫秒,向子线程传递{name: 'monkey'}信息
setInterval(function(){
worker.postMessage({name: 'monkey'});
},100);
//当主线程worker收到来自子线程的消息后,触发message事件
worker.onmessage = function(event){
document.getElementById('result').innerHTML+=event.data+"<br/>" ;
//主线程使用terminate方法中断与子线程来往,在浏览器中只能显示一次event.data
worker.terminate();
};
};
</script>
</head>
<body onload = "init()">
<div id="result"></div>
</body>
</html>
子线程worker.js代码:
//当主线程发来信息后,触发该message事件
onmessage = function(event){
//向主线程发送event.data.name信息
postMessage(event.data.name);
};
3、message
当有消息发送时,触发该事件。且,消息发送是双向的,消息内容可通过data来获取。
message使用,可见terminate中的demo
4、error
出错处理。且错误消息可以通过e.message来获取。
如下:
//worker = new Worker('url');
worker.onerror = function(e){
//打印出错消息
console.log(e.message);
//中断与子线程的联系
worker.terminate();
}
另:worker线程从上到下同步运行它的代码,然后进入异步阶段来对事件及计时器响应,如果worker注册了message事件处理程序,只要其有可能触发,worker就一直在内存中,不会退出,所以通信完毕后得手动在主线程中terminate或者子线程中close掉,但如果worker没有监听消息,那么当所有任务执行完毕(包括计数器)后,他就会退出。
三、worker上下文 |
先看下面这段代码:
主页面:
<!DOCTYPE html>
<head>
<title>worker</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script>
function init(){
var worker = new Worker('worker.js');
//接收消息事件
worker.onmessage = function(event){
console.log(event.data);
};
//错误信息事件
worker.onerror = function(e){
console.log('erro: ' + e.message);
//终止线程
worker.terminate();
};
};
</script>
</head>
<body onload = "init()"> </body>
</html>
worker.js
//window对象的alert方法
alert(1);
onmessage = function(event){
//向主线程发送event.data.name信息
postMessage(event.data.name);
};
执行上面代码结果:
为什么会这样呢?原因是alert为window对象的方法,所以会报错undefined。
worker.js执行的上下文,与主页面html执行时的上下文并不相同,最顶层的对象并不是window,woker.js执行的全局上下文,是个叫做WorkerGlobalScope的东东,所以无法访问window、与window相关的DOM API,但是可以与setTimeout、setInterval等协作。
WorkerGlobalScope作用域下的常用属性、方法如下:
1、self
我们可以使用 WorkerGlobalScope 的 self 属性来或者这个对象本身的引用
2、location
location 属性返回当线程被创建出来的时候与之关联的 WorkerLocation 对象,它表示用于初始化这个工作线程的脚步资源的绝对 URL,即使页面被多次重定向后,这个 URL 资源位置也不会改变。
3、close
关闭当前线程,与terminate作用类似
4、importScripts
我们可以通过importScripts()方法通过url在worker中加载库函数
5、XMLHttpRequest
有了它,才能发出Ajax请求
6、setTimeout/setInterval以及addEventListener/postMessage
四、关于worker |
我们可以做什么:
1.可以加载一个JS进行大量的复杂计算而不挂起主进程,并通过postMessage,onmessage进行通信
2.可以在worker中通过importScripts(url)加载另外的脚本文件
3.可以使用 setTimeout(), clearTimeout(), setInterval(), and clearInterval()
4.可以使用XMLHttpRequest来发送请求
5.可以访问navigator的部分属性
局限性:
1.不能跨域加载JS
2.worker内代码不能访问DOM
3.各个浏览器对Worker的实现不大一致,例如FF里允许worker中创建新的worker,而Chrome中就不行
4.IE这个新特性
浅谈webWorker的更多相关文章
- 浅谈 Fragment 生命周期
版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Fragment 文中如有纰漏,欢迎大家留言指出. Fragment 是在 Android 3.0 中 ...
- 浅谈 LayoutInflater
浅谈 LayoutInflater 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/View 文中如有纰漏,欢迎大家留言指出. 在 Android 的 ...
- 浅谈Java的throw与throws
转载:http://blog.csdn.net/luoweifu/article/details/10721543 我进行了一些加工,不是本人原创但比原博主要更完善~ 浅谈Java异常 以前虽然知道一 ...
- 浅谈SQL注入风险 - 一个Login拿下Server
前两天,带着学生们学习了简单的ASP.NET MVC,通过ADO.NET方式连接数据库,实现增删改查. 可能有一部分学生提前预习过,在我写登录SQL的时候,他们鄙视我说:“老师你这SQL有注入,随便都 ...
- 浅谈WebService的版本兼容性设计
在现在大型的项目或者软件开发中,一般都会有很多种终端, PC端比如Winform.WebForm,移动端,比如各种Native客户端(iOS, Android, WP),Html5等,我们要满足以上所 ...
- 浅谈angular2+ionic2
浅谈angular2+ionic2 前言: 不要用angular的语法去写angular2,有人说二者就像Java和JavaScript的区别. 1. 项目所用:angular2+ionic2 ...
- iOS开发之浅谈MVVM的架构设计与团队协作
今天写这篇博客是想达到抛砖引玉的作用,想与大家交流一下思想,相互学习,博文中有不足之处还望大家批评指正.本篇博客的内容沿袭以往博客的风格,也是以干货为主,偶尔扯扯咸蛋(哈哈~不好好工作又开始发表博客啦 ...
- Linux特殊符号浅谈
Linux特殊字符浅谈 我们经常跟键盘上面那些特殊符号比如(?.!.~...)打交道,其实在Linux有其独特的含义,大致可以分为三类:Linux特殊符号.通配符.正则表达式. Linux特殊符号又可 ...
- 浅谈Angular的 $q, defer, promise
浅谈Angular的 $q, defer, promise 时间 2016-01-13 00:28:00 博客园-原创精华区 原文 http://www.cnblogs.com/big-snow/ ...
随机推荐
- 《HTTP权威指南》大块儿头
看到这样的一本书,胡乱翻开看看里面的内容,我觉得我又浮躁了.真厚啊!能学多少就学多少吧. 看看提要,这本书主要想讲的是HTTP和相关Web技术的.关于这方面的内容,知道的不多.
- asp.net mvc引用控制台应用程序exe
起因:有一个控制台应用程序和一个web程序,web程序想使用exe程序的方法,这个时候就需要引用exe程序. 报错:使用web程序,引用exe程序 ,vs调试没有问题,但是部署到iis就报错,如下: ...
- chm文件索引丢失和不能搜索
regsvr32 hhctrl.ocx regsvr32 itss.dll regsvr32 itircl.dll
- 使用THINKPHP中的控制器和模块查询数据库
1,自定义一个UserController的控制器,导入tp的控制器与模块执行相应的操作. ----var_dump()方法是判断一个变量的类型与长度,并输出变量的数值,如果变量有值输的是变量的值. ...
- SpringMVC 框架的搭建及基本功能的实现
首先新建一个WEB项目 导入jar包 我们基于Spring mvc框架进行开发,需要依赖一下的spring jar包: spring-aop-4.0.4.RELEASE.jar spring-bean ...
- fasicon.js (无二维码版,如需要js创建二维码版本可联系我:770959294@qq.com)
/*** Created by 张云山 on 2016/12/9.*/(function(wins,doct){wins.fasicon = function(){this.name = " ...
- properties文件使用{0}...
例如properties文件的配置 weixin.token.url=https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credent ...
- Second Day: 关于Button监听事件的三种方法(匿名类、外部类、继承接口)
第一种:通过匿名类实现对Button事件的监听 首先在XML文件中拖入一个Button按钮,并设好ID,其次在主文件.java中进行控件初始化(Private声明),随后通过SetOnClickLis ...
- 分区里的inode号是0号和1号的block
分区里的inode号是0号和1号的block 我相信大家在使用Linux的时候都遇到过误删文件系统数据的情况,不管是自己误删还是帮人家恢复误删 现在用的比较多的恢复工具大概是ext3grep .ext ...
- Javascript基础回顾 之(一) 类型
本来是要继续由浅入深表达式系列最后一篇的,但是最近团队突然就忙起来了,从来没有过的忙!不过喜欢表达式的朋友请放心,已经在写了:) 在工作当中发现大家对Javascript的一些基本原理普遍存在这里或者 ...