(吐槽:浏览器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. CTF实战(隐写术):欢迎来到地狱

    前言:请登录实验吧开启刷题模式,拿到的flag返回该网站验证正确性. 下载“欢迎来到地狱”CTF题目(总共三个文件

  2. STM32窗口看门狗和独立看门狗的区别,看门狗介绍及代码演示

    一.介绍: STM32看门狗分为独立看门狗和窗口看门狗两种,其两者使用调条件如下所示, IWDG和WWDG两者特点如下图所示: 独立看门狗的手册资料: 窗口看门狗的手册资料:             ...

  3. BZOJ 4511 洛谷3131 USACO 16.Jan 七子共

    用sum[i]表示前缀和模7的值,若存在i≤j,满足sum[i]==sum[j],则区间(i,j]的和为7的倍数. O(N)扫出sum[0]~sum[6]第一次出现的位置first和最后一次出现的次数 ...

  4. 【郑轻邀请赛 F】 Tmk吃汤饭

    [题目链接]:https://acm.zzuli.edu.cn/zzuliacm/problem.php?id=2132 [题意] [题解] 很容易想到用队列来模拟; 这个队列维护的是正在煮的4个人煮 ...

  5. 清北学堂模拟赛d7t6 拯救世界

    分析:如果题目中没有环的话就是一道裸的最长路的题目,一旦有环每个城市就会被救多次火了.把有向有环图变成有向无环图只需要tarjan一边就可以了. #include <bits/stdc++.h& ...

  6. HDU 5433

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

  7. BZOJ 1605 [Usaco2008 Open]Crisis on the Farm 牧场危机 DP

    题意:链接 方法: DP 解析: 第一眼搜索题,复杂度不同意dfs,并且牛的数量太多不能bfs,迭代更不可能,A*不会估价.可能记忆化? 等等记忆化我还搜个毛线- 直接改成DP就好了. 状态非常好想非 ...

  8. SQL Server 2012内部原理及故障排除(专栏)

    PROFESSIONAL SQL SERVER® 2012 INTERNALS AND TROUBLESHOOTING一书(可从这里下载).认为内容非常不错.自己也想对SQL Server 2012有 ...

  9. QueryString 地址栏参数

    MXS&Vincene  ─╄OvЁ  &0000002 ─╄OvЁ  MXS&Vincene MXS&Vincene  ─╄OvЁ:今天很残酷,明天更残酷,后天很美好 ...

  10. OpenCV 学习(计算图像的直方图)

    OpenCV 计算图像的直方图 计算图像的直方图是图像处理领域一个非经常见的基本操作. OpenCV 中提供了 calcHist 函数来计算图像直方图.只是这个函数说实话挺难用的,研究了好久才掌握了些 ...