(吐槽:浏览器js终于进入多线程时代!)

  以前利用setTimeout、setInterval等方式的多线程,是伪多线程,本质上是一种在单线程中进行队列执行的方式。自从html5 web worker出现,js真正进入了多线程编程时期,现在就开始js的“真·多线程”秘籍修炼吧!

最近因为工作中的需要,使用了html5的web worker,之前一直对worker一知半解。直到看到IBM上的一篇博文(知识不是完全有效,可以当作参考),才对worker有了基本概念。

worker分类

worker分为专用线程和共享线程。专用线程只能在当前页面中访问到。而如果要多个页面访问同一个worker,就要使用共享线程,但前提是这几个页面是同域的。

worker基本用法

一、专用线程

  1、在浏览器线程中(即插入页面的js代码,内联、外链的js代码都可以):

 var worker=new Worker("testWorker.js");

 worker.onmessage=function(event){
  /*收到worker线程发送来的数据*/
  console.log(event.data);
}; worker.onerror=function(event){
  /*收到worker线程发送来的错误信息*/
  console.log(event.data);
}; worker.postMessage("some data");/*向worker线程发送数据*/

      worker一直处于监听状态,要释放这个线程必须在浏览器线程调用worker.terminate();以释放资源。

  2、在worker线程代码中:

 this.onmessage=function(event){
/*收到浏览器线程发来的信息,然后回复浏览器线程*/
this.postMessage("worker received data:"+event.data+"("+new Date()+")";
};

      在worker线程中,如果不用接收浏览器线程发来数据或者浏览器线程不发送数据,则可以直接执行处理,最后this.postMessage(/*data*/)就行了。

      在上例中,this指线程对象,所以最好的用法是在第一行代码的前面加上“var thread=this;”,然后就可以在任何地方使用thread.postMessage和thread.onmessage方法。worker线程中的代码变成:

 var thread=this;
thread.onmessage=function(event){
/*收到浏览器线程发来的信息,然后回复浏览器线程*/
thread.postMessage("worker received data:"+event.data+"("+new Date()+")";
};

二、共享线程

  1、浏览器线程中:

 var sharedWorker=new SharedWorker("sharedWorker.js");

 worker.onerror=function(e){
/*worker对象错误*/
console.log("create shared worker error.");
};
worker.port.onmessage=function(event){
console.log(event.data);
};
worker.port.onerror=function(e){
/*worker通信、worker线程中的错误*/
console.log(e.message);
}; worker.port.start();/*必须执行start以开始连接*/

    在浏览器线程中,通信是通过worker的port对象进行的,每一个页面的port是不同的,具有唯一性。最关键的一点是start(),这个函数表示开始连接shared worker,连接成功时,worker线程将增加一个连接数。

    在同域下的其他页面调用此shared worker,代码结构与此相同,只是处理数据的逻辑可能不同。

  2、worker线程中:

 var thread=this,
connectionCount=0;
thread.onconnect=function(e) {
/*有页面请求连接触发*/
var port=e.ports[0];/*获取指定页面的port,用这个port和页面通信*/
port.postMessage("new connection,index:"+connectionCount);
port.onmessage=function(event) {
port.postMessage("received data:"+event.data);
};
connectionCount++;
};

    在worker代码中,在onconnect回调函数中获取请求连接者的连接对象port,然后就可以通过这个port与请求者通信。

    在这里,可以把port缓存起来,以后worker可以随时主动postMessage给浏览器特定的页面线程。这需要页面发送自己的“全局唯一特征码”供worker识别。

生命周期

  专用线程的生命周期与页面的生命周期一致,可以使用worker.terminate()关闭释放线程。

  共享线程的生命周期与其连接数相关,当连接数为0时,将自动关闭释放。如果需要关闭当前页面的连接,可以调用worker.port.close(),worker线程中的连接数将减少一个。关闭页面也和调用worker.port.close具有同样的影响。

尾记

  1、worker也和服务器端的多线程一样,创建、销毁开销较大。所以,worker只应该用于耗时操作,例如复杂、长时间的运算。

  2、worker不能访问DOM及页面相关对象如window document,这也在一定程度上限制了worker的应用,也不能在worker中创建worker。

  3、worker中可以使用XMLHttpRequest,可以自己写一个包装http请求的对象到worker线程代码中,或者找个开源的http库。使用开源库需要解决如何引入的问题,还没有研究。

  4、可以动态创建worker代码。提供思路,具体怎么做的忘了:)       ------------      将需要运行的代码转换为字符串,再转换为二进制的Blob对象,再使用window.URL.createObjectURL创建动态url,参数是Blob对象,然后将这个动态url传入worker的构造函数,作为第一个参数。这种一般是用在专用线程上。例子如下。

 var doWorkByHtml5Worker = (function () {
//使用html5的worker进行后台耗时耗Cpu计算
var worker, urlContext = window.URL || window.webkitURL || window.mozURL || window.msURL;
var blobBuilder, blobBuilderContext = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder;
if (blobBuilderContext) {
var clearBlob = function () {
blobBuilder = null;
blobBuilder = new blobBuilderContext();
blobBuilder.clear = clearBlob;
};
clearBlob();
} else if (Blob) {
blobBuilder = {
builder: null,
append: function (str) {
this.builder = new Blob([str]);
},
getBlob: function () {
return this.builder;
},
clear: function () {
this.builder = null;
}
}
} return {
/*
* workFunc为需要运行的函数,可以是字符串,也可以是原型函数,如果是函数,将在内部转换为字符串。必须为函数形式。
* params为需要传入函数的参数
* callback为执行完毕的回调函数,参数为执行workFunc返回的值
*/
Do: function (workFunc, params, callback) {
var workStr = workFunc.toString();
if (workFunc !== workStr) {
workFunc = workStr;
}
blobBuilder.append('postMessage((' + workFunc.toString() + ')(' + JSON.stringify(params) + '));');
worker = new Worker(urlContext.createObjectURL(blobBuilder.getBlob()));
worker.onmessage = function (e) {
this.terminate();
worker = null;
blobBuilder.clear();
callback && callback(e.data);
};
}
};
})();

  使用:

 /*基本演示*/
doWorkByHtml5Worker.Do(
function(){
return "data from custom function";
},
null,
function(data){
/*回调*/
console.log(data);/*将打印字符串"data from custom function"*/
}
); /*带参数演示*/
doWorkByHtml5Worker.Do(
function(obj){
return "received object:{id:"+obj.id+",msg:\""+obj.msg+"\"}";
},
{id:0,msg:"go home"},
function(data){
/*回调*/
console.log(data);/*将打印字符串"received object:{id:0,msg:"go home"}"*/
}
); /*传入字符串型执行函数*/
var doSomething=(function(){
return "data from custom function";
}).toString();
/* 或者:var doSomething="function(){return \"data from custom function\";}";*/
doWorkByHtml5Worker.Do(
doSomething,
null,
function(data){
/*回调*/
console.log(data);/*将打印字符串"data from custom function"*/
}
);

参考:

1、菜鸟教程

2、IBM博文

3、W3C文档

html5 web worker学习笔记(记一)的更多相关文章

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

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

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

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

  3. JavaScript多线程之HTML5 Web Worker

    在博主的前些文章Promise的前世今生和妙用技巧和JavaScript单线程和浏览器事件循环简述中都曾提到了HTML5 Web Worker这一个概念.在JavaScript单线程和浏览器事件循环简 ...

  4. 【前端】移动端Web开发学习笔记【2】 & flex布局

    上一篇:移动端Web开发学习笔记[1] meta标签 width设置的是layout viewport 的宽度 initial-scale=1.0 自带 width=device-width 最佳实践 ...

  5. 【前端】移动端Web开发学习笔记【1】

    下一篇:移动端Web开发学习笔记[2] Part 1: 两篇重要的博客 有两篇翻译过来的博客值得一看: 两个viewport的故事(第一部分) 两个viewport的故事(第二部分) 这两篇博客探讨了 ...

  6. 【前端】Web前端学习笔记【2】

    [2016.02.22至今]的学习笔记. 相关博客: Web前端学习笔记[1] 1. this在 JavaScript 中主要有以下五种使用场景 在全局函数调用中,this 绑定全局对象,浏览器环境全 ...

  7. 【前端】Web前端学习笔记【1】

    ... [2015.12.02-2016.02.22]期间的学习笔记. 相关博客: Web前端学习笔记[2] 1. JS中的: (1)continue 语句 (带有或不带标签引用)只能用在循环中. ( ...

  8. ASP.NET MVC Web API 学习笔记---第一个Web API程序

    http://www.cnblogs.com/qingyuan/archive/2012/10/12/2720824.html GetListAll /api/Contact GetListBySex ...

  9. Web前端学习笔记(001)

    ....编号    ........类别    ............条目  ................明细....................时间 一.Web前端学习笔记         ...

随机推荐

  1. 1.1 Java程序设计平台

    Java并不只是一种语言.在此之前出现的那么多中语言也没有能够引起那么大的轰动.Java是一个完整的平台,有一个庞大的库,其中包含了很多可重用的代码和一个提供诸如安全性.跨操作系统的可移植性以及自动垃 ...

  2. 【codeforces 796D】Police Stations

    [题目链接]:http://codeforces.com/contest/796/problem/D [题意] 在一棵树上,保证每个点在距离d之内都有一个警察局; 让你删掉最多的边,使得剩下的森林仍然 ...

  3. 基于Ubuntu系统的Tomcat部署项目

    第一步.拿到项目war包 第二步.上传到服务器/var/lib/tomcat8/webapps/ROOT目录下 第三步.使用命令解压war包 jar -xvf star1.0.0.war 第三步.重启 ...

  4. Spring Boot 内嵌容器 Tomcat / Undertow / Jetty 优雅停机实现

    Spring Boot 内嵌容器 Tomcat / Undertow / Jetty 优雅停机实现 Anoyi 精讲JAVA 精讲JAVA 微信号 toooooooozi 功能介绍 讲解java深层次 ...

  5. 【无限滚动加载数据】—infinite-scroll插件的使用

    网上对于infinite-scroll插件使用的例子不多.但由于它的出现,鼓吹了瀑布流形式的页面展示方式,所以不得不了解了解这种新的分页方式. 官网上有对infinite-scroll的详细描述,但一 ...

  6. [Poj3261] [Bzoj1717] [后缀数组论文例题,USACO 2006 December Gold] Milk Patterns [后缀数组可重叠的k次最长重复子串]

    和上一题(POJ1743,上一篇博客)相似,只是二分的判断条件是:是否存在一段后缀的个数不小于k #include <iostream> #include <algorithm> ...

  7. Jquery书写ajax

    根据API学习本章 Jquery书写ajax 使用ajax发送表单到servlet,发送时显示等待图片,servlet处理完返回信息,在页面显示返回信息,并且隐藏等待图片 <%@ page la ...

  8. [bzoj1941][Sdoi2010]Hide and Seek_KD-Tree

    Hide and Seek bzoj-1941 Sdoi-2010 题目大意:给出平面上n个点,选出一个点,使得距离这个点的最远点曼哈顿距离减去距离这个点的最近非己点的曼哈顿距离最小.输出最小曼哈顿距 ...

  9. [bzoj1468][poj1741]Tree_点分治

    Tree bzoj-1468 poj-1741 题目大意:给你一颗n个点的树,求树上所有路径边权和不大于m的路径条数. 注释:$1\le n\le 4\cdot 10^4$,$1\le m \le 1 ...

  10. cogs 315. [POJ3255] 地砖RoadBlocks

    315. [POJ3255] 地砖RoadBlocks ★★★   输入文件:block.in   输出文件:block.out   简单对比时间限制:1 s   内存限制:128 MB Descri ...