【worker】js中的多线程
因为下个项目中要用到一些倒计时的功能,所以就提前准备了一下,省的到时候出现一下界面不友好和一些其他的事情。正好趁着这个机会也加深一下html5中的多线程worker的用法和理解。
Worker简介
JavaScript 语言采用的是单线程模型,也就是说,所有任务只能在一个线程上完成,一次只能做一件事。前面的任务没做完,后面的任务只能等着。这些都是我们所公知的。但是随着业务的不断增加,只是单纯的单线程模式已经可能无法满足我们的需求了。于是在html5中新增了后台任务worker API。
w3c中的介绍:web worker 是运行在后台的 JavaScript,独立于其他脚本,不会影响页面的性能。您可以继续做任何愿意做的事情:点击、选取内容等等,而此时 web worker 在后台运行。
worker就是为了JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。开启后台线程,在不影响前台线程的前提下做一些耗时或者异步的操作。因为是不同的线程,所以主线程与worker线程互不干扰。也不会相互打断。所以在一些场景可以提高页面的流程性。Worker 线程一旦新建成功,就会始终运行,不会被主线程上的活动(比如用户点击按钮、提交表单)打断。这样有利于随时响应主线程的通信。但是,这也造成了 Worker 比较耗费资源,不应该过度使用,而且一旦使用完毕,就应该关闭。
使用规则
- 必须同源:也就是说js文件的路径必须和主线程的脚本同源。防止了外部引用。
- dom限制:在worker线程中不能操作dom(document,window,parent)。注意可以使用浏览器的navigator和location对象。
- 通讯限制:worker线程和主线程不在一个上下文中所以不能直接通讯。也就是说主线程定义的变量在worker中也是不能使用的。所有只能通过消息完成。
- 提示禁止:worker线程不能alert和confirm,这个不知到具体原因?
- 传值dom:进行消息通讯也不能传值dom只能是变量。
- ie限制:ie9不能使用!ie9不能使用!ie9不能使用!
worker文档
Web Workers API的Worker界面代表了一个可以轻松创建的后台任务,可以将消息发送回其创建者。创建worker就像调用 构造函数并指定要在工作线程中运行的脚本一样简单。
构造函数
worker():创建一个专用的Web worker,在指定的URL上执行脚本。示例:var worker=new Worker('js/setTime.js');
属性
onerror:
这是一个在error事件发生时调用的函数,并且通过该函数冒泡worker。示例:worker.onerror=function(){....};
onmessage:
这是一个worker中message事件要发生的时候调用的事件。 示例:worker.onmessage=function(){....};
这个事件一般与postMessage事件同时使用,一个用来发送数据,一个用来接受数据。例如:
主线程中:
var jsId = "00001";
var worker = new Worker('js/setTime.js');
worker.postMessage(jsId);
worker线程中:
//接受事件参数
onmessage = function(e) { console.log(e.data[0])
}
这样就完成了一个主线程向worker线程传递参数的过程。同样如果worker线程要向主线程传递参数反过来写即可。
onmessageerror:
在消息传递过程出现错误的属性事件。示例:worker.onmessageerror=function(){....};
方法
postMessage:
向线程worker的内部范围发送消息,可以设置参数,发送给worker线程的数据。在onmessage中接受。
terminate:
过多的开启worker线程非常浪费资源所以在使用过后可以终止它,终止方法使用terminate()。示例:worker.terminate();
close:
除了上面的关闭,如果是在worker线程自身也可以使用self.close()关闭。
计时器示例
上面说了那么多都是介绍worker的一些基本属性或者方法的使用。下面通过具体的示例来看效果。
我们就拿最常用的倒计时来做示例说明。很简单的一个例子。我们在业务中经常遇到倒计时业务,在倒计时的时候还要做一些其他的业务。因为js单线程的特性,你会发现你的倒计时在你进行其他业务操作的时候是暂停了的。例如现在是9:57你进行了三秒的业务处理。等业务处理完成应该是:9:54,但是你的倒计时还是9:57.就很明显的说明了这一个现象。
场景业务设计
那么我们现在设计这么一个业务操作,
- 首先我们页面有一个定时器和一个业务操作按钮(用来模拟耗时的操作)。
- 然后把定时器写到一个worker中进行倒计时操作。
- 最后通过消息通讯把每次的倒计时时间发送给主线程让主线程修改显示时间。
- 结束倒计时完毕结束定时器和线程
有人可能会说为什么还要回到主线程修改时间显示值,请看一下上面的使用规则,我本来也是打算进行主线程传值dom给worker线程奈何不行只能在回传回来。
代码展示
Html代码:
<body>
<div>
<span id="Minute_p">10</span> :
<span id="Second_p">00</span>
</div> <button type="button" onclick="business()">耗时操作</button>
</body>
主线程js代码:
//页面加载完成后初始化
window.onload = function() {
//创建定时器线程
var worker = new Worker('js/setTime.js');
//获取dom对象
var domMinute_p = document.getElementById('Minute_p');
var domSecond_p = document.getElementById('Second_p');
worker.postMessage(600); //这里可以接受worker线程的返回值
worker.onmessage = function(event) {
var totalSecond = event.data;
console.log(totalSecond)
//计算分钟数
var minute_p = parseInt(totalSecond / 60);
domMinute_p.innerText = minute_p;
//计算秒数
var second_p = parseInt(totalSecond % 60);
domSecond_p.innerText = second_p;
}
}
//这里是模拟的耗时操作
function business() {
var data = [1, 2, 3, 4, 5];
for(var i = 1; i < 1000; i++) {
for(var j = 1; j < 1000; j++) {
for(var k = 1; k < 5000; k++) {
var b = k * 100;
}
}
}
console.log("业务终于走完了!")
}
worker线程js代码:
var totalSecond = 600;
var domMinute_p, domSecond_p, //接受事件参数
onmessage = function(e) {
console.log(e.data)
domMinute_p = e.data;
}
var timeId = setInterval(function() {
totalSecond--; if(totalSecond == 0) {
self.close();
}
console.log(totalSecond)
postMessage(totalSecond) }, 1000)
好了大致示例就是这么多。下面是截图效果:

开始运行后编号1会开始倒计时,但是当你点击了编号2进行了模拟耗时后,编号1还是会卡住,只有完成编号2后才会运行,但是不同与上面说到的单线程是,他再次运行时的时间是正确时间,还是刚才的例子如果是9:57,点击编号2模拟耗时了3秒,耗时完成后编号1会显示9:54而不是单线程的9:57。就说明worker现在在耗时操作的时候是持续运行的,时间卡只不过是主线程的dom操作被卡住了而已(可以把耗时业务也开启worker就不卡住了)。这里只是介绍worker的使用,所有就不纠结这个界面显示的问题。
补充界面显示方法:
后来有些人就问我怎弄界面显示,我还是真的心疼你们啊,不知道举一反三吗,当然是吧业务耗时也放到后台线程啊,哈哈!!!
再特此说明一个问题,仅在安卓测试:就是定时器在息屏模式下仍继续执行
我还是上面的例子做个例子:
把耗时业务放到business.js文件
onmessage = function(e) {
console.log(e.data)
for(var i = ; i < ; i++) {
for(var j = ; j < ; j++) {
for(var k = ; k < ; k++) {
var b = k * ;
}
}
}
console.log("耗时业务走完了");
postMessage()
}
然后主文件js调用就好了啊:
//这里是模拟的耗时操作
function business() {
var worker = new Worker('js/business.js');
worker.postMessage("开启任务耗时");
worker.onmessage = function(event) {
if(event == ) {
console.log("点击一次完成")
worker.terminate()
} }
}
截图效果:


【worker】js中的多线程的更多相关文章
- three.js 中使用多线程以及性能测试
今天郭先生说一下WebWorker以及WebWorker在three.js中的应用.我们都知道Javascript是单线程的,比如执行js代码的同时UI渲染就会停止,对于多核CPU的点脑,这一点让人难 ...
- Web worker 与JS中异步编程的对比
0.从一道题说起 var t = true; setTimeout(function(){ t = false; }, 1000); while(t){ } alert('end'); 问,以上代码何 ...
- 深入HTML5 Web Worker应用实践:多线程编程
HTML5 中工作线程(Web Worker)简介 至 2008 年 W3C 制定出第一个 HTML5 草案开始,HTML5 承载了越来越多崭新的特性和功能.它不但强化了 Web 系统或网页的表现性能 ...
- JS中的异步以及事件轮询机制
一.JS为何是单线程的? JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事.那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊.(在JAVA和c#中的异步 ...
- 深入 HTML5 Web Worker 应用实践:多线程编程
深入 HTML5 Web Worker 应用实践:多线程编程 HTML5 中工作线程(Web Worker)简介 至 2008 年 W3C 制定出第一个 HTML5 草案开始,HTML5 承载了越来越 ...
- 【面试篇】寒冬求职季之你必须要懂的原生JS(中)
互联网寒冬之际,各大公司都缩减了HC,甚至是采取了“裁员”措施,在这样的大环境之下,想要获得一份更好的工作,必然需要付出更多的努力. 一年前,也许你搞清楚闭包,this,原型链,就能获得认可.但是现在 ...
- 疯狂Html+CSS+JS 中JS总结
来自:http://mzkmzk.github.io/blog/2015/10/05/amazeing-js/ 0 总结 本书的JS 第一章有讲语法有挺多常见的坑点和原理解释很不错 第二章DOM编程讲 ...
- js中的webworker
js中的webworker webworker的作用类似于java的多线程 以独立文件的形式运行webworker index.html <!DOCTYPE html> <html ...
- JavaScript 中的多线程通信的方法
在Html 5诞生之后,我们可以使用javascript来实现多线程处理.H5 新增了一个web workers api,使用这个API,用户可以很容易地创建在后台运行的线程,H5 中被称为workd ...
随机推荐
- MySQL基础知识3
- 10-Mock模拟接口返回数据
1.安装mock 方法一:pip安装 命令行直接输入:pip install mock 方法二:官网下载mock安装包安装 下载安装包后,解压,命令行进入解压目录,执行python setup.py ...
- 从构建分布式秒杀系统聊聊WebSocket推送通知
秒杀架构到后期,我们采用了消息队列的形式实现抢购逻辑,那么之前抛出过这样一个问题:消息队列异步处理完每个用户请求后,如何通知给相应用户秒杀成功? 场景映射 首先,我们举一个生活中比较常见的例子:我们去 ...
- Android 9.0/P 开发问题及解决方案汇总
一.使用 org.apache.http.legacy 库在Android 9.0上运行出现崩溃 日志内容: java.lang.NoClassDefFoundError: Failed resolu ...
- Java学习笔记三:运算符
1.算术运算符: GitHub代码练习地址:https://github.com/Neo-ML/JavaPractice/blob/master/OperPrac01.java + - * / ...
- PDF 报表 Java 组件 iText5 中的单位注意事项
这里面涉及到这几个单位: 点(磅)(pt).像素(px).英寸(inch).毫米(mm) 分辨率单位有: dpi(点每英寸):出现于打印或印刷领域. lpi (线每英寸):描述光学分辨率的尺度. pp ...
- Java工程师必备
Java工程师必备 JAVA基础扎实,熟悉JVM,熟悉网络.多线程.分布式编程及性能调优 精通Java EE相关技术 熟练运用Spring/SpringBoot/MyBatis等基础框架 熟悉分布式系 ...
- 4-3 组件参数校验与非props特性
本文参考脚本之家,https://www.jb51.net/article/143466.htm 通过属性的形式,父组件对子组件进行参数的传递 //如下图: //父组件设置content属性,向属性中 ...
- logstash收集syslog日志
logstash收集syslog日志注意:生产用syslog收集日志!!! 编写logstash配置文件 #首先我用rubydebug测试数据 [root@elk-node1 conf.d]# cat ...
- DDD实战进阶第一波(十四):开发一般业务的大健康行业直销系统(订单上下文应用服务用例与接口)
上一篇文章我们主要讲了订单上下文的领域逻辑,在领域逻辑中完成了订单项的计算逻辑.订单的计算逻辑以及如何生成相应的实体code,这篇文章我们通过 在应用服务中实现一个下单的用例,来将这些领域逻辑以及仓储 ...