因为下个项目中要用到一些倒计时的功能,所以就提前准备了一下,省的到时候出现一下界面不友好和一些其他的事情。正好趁着这个机会也加深一下html5中的多线程worker的用法和理解。

Worker简介

JavaScript 语言采用的是单线程模型,也就是说,所有任务只能在一个线程上完成,一次只能做一件事。前面的任务没做完,后面的任务只能等着。这些都是我们所公知的。但是随着业务的不断增加,只是单纯的单线程模式已经可能无法满足我们的需求了。于是在html5中新增了后台任务worker API。

w3c中的介绍:web worker 是运行在后台的 JavaScript,独立于其他脚本,不会影响页面的性能。您可以继续做任何愿意做的事情:点击、选取内容等等,而此时 web worker 在后台运行。

worker就是为了JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。开启后台线程,在不影响前台线程的前提下做一些耗时或者异步的操作。因为是不同的线程,所以主线程与worker线程互不干扰。也不会相互打断。所以在一些场景可以提高页面的流程性。Worker 线程一旦新建成功,就会始终运行,不会被主线程上的活动(比如用户点击按钮、提交表单)打断。这样有利于随时响应主线程的通信。但是,这也造成了 Worker 比较耗费资源,不应该过度使用,而且一旦使用完毕,就应该关闭。

使用规则

  1. 必须同源:也就是说js文件的路径必须和主线程的脚本同源。防止了外部引用。
  2. dom限制:在worker线程中不能操作dom(document,window,parent)。注意可以使用浏览器的navigator和location对象。
  3. 通讯限制:worker线程和主线程不在一个上下文中所以不能直接通讯。也就是说主线程定义的变量在worker中也是不能使用的。所有只能通过消息完成。
  4. 提示禁止:worker线程不能alert和confirm,这个不知到具体原因?
  5. 传值dom:进行消息通讯也不能传值dom只能是变量。
  6. 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中的多线程的更多相关文章

  1. three.js 中使用多线程以及性能测试

    今天郭先生说一下WebWorker以及WebWorker在three.js中的应用.我们都知道Javascript是单线程的,比如执行js代码的同时UI渲染就会停止,对于多核CPU的点脑,这一点让人难 ...

  2. Web worker 与JS中异步编程的对比

    0.从一道题说起 var t = true; setTimeout(function(){ t = false; }, 1000); while(t){ } alert('end'); 问,以上代码何 ...

  3. 深入HTML5 Web Worker应用实践:多线程编程

    HTML5 中工作线程(Web Worker)简介 至 2008 年 W3C 制定出第一个 HTML5 草案开始,HTML5 承载了越来越多崭新的特性和功能.它不但强化了 Web 系统或网页的表现性能 ...

  4. JS中的异步以及事件轮询机制

    一.JS为何是单线程的? JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事.那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊.(在JAVA和c#中的异步 ...

  5. 深入 HTML5 Web Worker 应用实践:多线程编程

    深入 HTML5 Web Worker 应用实践:多线程编程 HTML5 中工作线程(Web Worker)简介 至 2008 年 W3C 制定出第一个 HTML5 草案开始,HTML5 承载了越来越 ...

  6. 【面试篇】寒冬求职季之你必须要懂的原生JS(中)

    互联网寒冬之际,各大公司都缩减了HC,甚至是采取了“裁员”措施,在这样的大环境之下,想要获得一份更好的工作,必然需要付出更多的努力. 一年前,也许你搞清楚闭包,this,原型链,就能获得认可.但是现在 ...

  7. 疯狂Html+CSS+JS 中JS总结

    来自:http://mzkmzk.github.io/blog/2015/10/05/amazeing-js/ 0 总结 本书的JS 第一章有讲语法有挺多常见的坑点和原理解释很不错 第二章DOM编程讲 ...

  8. js中的webworker

    js中的webworker webworker的作用类似于java的多线程 以独立文件的形式运行webworker index.html <!DOCTYPE html> <html ...

  9. JavaScript 中的多线程通信的方法

    在Html 5诞生之后,我们可以使用javascript来实现多线程处理.H5 新增了一个web workers api,使用这个API,用户可以很容易地创建在后台运行的线程,H5 中被称为workd ...

随机推荐

  1. Maven 在新版eclipse报错的解决

    转自Stack Overflow Remove all your failed downloads: Linux: find ~/.m2 -name "*.lastUpdated" ...

  2. 背水一战 Windows 10 (102) - 应用间通信: 剪切板

    [源码下载] 背水一战 Windows 10 (102) - 应用间通信: 剪切板 作者:webabcd 介绍背水一战 Windows 10 之 应用间通信 剪切板 - 基础, 复制/粘贴 text ...

  3. 【BZOJ4883】 [Lydsy1705月赛]棋盘上的守卫(最小生成树,基环树)

    传送门 BZOJ Solution 考虑一下如果把行,列当成点,那么显然这个东西就是一个基环树对吧. 直接按照\(Kruscal\)那样子搞就好了. 代码实现 代码戳这里

  4. linux创建用户并设置密码

    1.在root权限下,useradd只是创建了一个用户名,如(useradd+用户名),它并没有在/home目录下创建同名文件夹,也没有创建密码,因此利用这个用户登录系统,是登录不了的,为了避免这样的 ...

  5. 第73节:Java中的HTTPServletReauest和HTTPServletResponse

    第73节:Java中的HTTPServletReauest和HTTPServletResponse HTTP协议 客户端与服务器端通讯的一种规则. request: 请求行 请求头 请求体 respo ...

  6. 项目笔记:2018年4月(SpringCloud架构和SpringBoot框架)

    一.启动Euerka服务 1.在启动类里用@propertySource引入全局配置文件noteapp-service.properties: 如上图.左侧为某服务配置文件properties,右侧为 ...

  7. 基于C++Qt4开发的白鸽局域网聊天器

    开源项目Github链接:https://github.com/u014427391/chitchat1.0 欢迎star (1)群聊主界面,有工具栏,工具栏功能分别是发送文件.打开音乐播放器.保存聊 ...

  8. 使用PageHepler分页

    首先需要引入依赖 <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>p ...

  9. android发布新版忘记keystore(jks)密码终极解决方案

    android app签名是使用的keystore文件/jks文件,如果是eclipse是keystore,android studio则是jks,如果忘记了的话很悲催: 1.找到密码 2.改应用的包 ...

  10. redux源码学习笔记 - createStore

    本篇是学习redux源码的一些记录,学习的redux版本是^4.0.1. 在页面开发时,需要管理很多状态(state),比如服务器响应,缓存数据,UI状态等等···当页面的庞大时,状态就会变的混乱.r ...