(吐槽:浏览器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. linux安装openjdk

    使用yum查找jdk: yum search java | grep jdk 执行安装命令:yum install java-1.8.0-openjdk

  2. 取代PHP原生函数的一些扩展包

    前言 虽然程序员无时无刻都在造轮子,但造轮子也有效率之分,用好轮子才能造出好"

  3. 基本数据类型:字符串(str)

    一.字符串的定义和创建 字符串是一个有序的字符的集合,用于存储和表示基本的文本信息,' '或'' ''或''' '''中间包含的内容称之为字符串,总之加了引号的字符都被认为是字符串! 创建: > ...

  4. (问题待解决)sql查询不显示前置‘0’的问题

    SELECT * , ,),() ) ' end)) from CourseBooksNotes ),)),)+'秒'; ),)),)),)+'秒'

  5. 【codeforces 510A】Fox And Snake

    [题目链接]:http://codeforces.com/contest/510/problem/A [题意] 让你画一条蛇.. [题解] 煞笔提 [Number Of WA] 0 [完整代码] #i ...

  6. MG loves string

    MG loves string Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others ...

  7. Java SE 之 递归方法

    public void removeSon(String id, List<Dept> deptList) { String hql = "from Dept where par ...

  8. [bzoj4282]慎二的随机数列_动态规划_贪心

    慎二的随机数列 bzoj-4282 题目大意:一个序列,序列上有一些数是给定的,而有一些位置上的数可以任意选择.问最长上升子序列. 注释:$1\le n\le 10^5$. 想法:结论:逢N必选.N是 ...

  9. [bzoj1592][Usaco09Feb]Making the Grade 路面修整_动态规划

    Making the Grade 路面修整 bzoj-1592 题目大意:给你n段路,每段路有一个高度h[i],将h[i]修改成h[i]$\pm\delta$的代价为$\delta$,求将这n段路修成 ...

  10. HDU 5433

    每次BC都好心酸... BFS+queue..状态可以设为p_val[x][y][k],加上斗志的值. #include <iostream> #include <cstdio> ...