浅谈webWorker

一、webWorker之初体验

"setTimeout那些事儿"中,说到JavaScript是单线程。也就是同一时间只能做同一事情。

也好理解,作为浏览器脚本语言,如果JavaScript不是单线程,那么就有点棘手了。比如,与用户交互或者对DOM进行操作时,在一个线程上修改某个DOM,另外的线程删除DOM,这时浏览器该如何抉择呢?

所以,JavaScript是单线程也是有背景的。

如下:

<!DOCTYPE html>
    <head>
        <title>singleThread</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    </head>
    <body>
        <script>
            //添加到任务队列中,待同步任务所处的‘执行栈’执行完毕,1秒后执行任务队列中的这个匿名函数            setTimeout(function(){
                console.log(‘come on‘);
            },1000);            //只要不关闭该alert,‘执行栈’就没结束,从而也就不会进入到任务队列中            alert(‘waiting‘);        </script>
    </body></html>

但,HTML5引入了一个工作线程(webWorker)的概念。它允许开发人员编写能够长时间运行而不被用户所中断的后台程序,去执行事务或者逻辑,并同时保证页面对用户的响应。

简而言之,就是允许JavaScript创建多个线程,但是子线程完全受主线程控制,且不得操作DOM

从而,可以用webWorker来处理一些比较耗时的计算。

如下,主页面:

<!DOCTYPE html>
    <head>
        <title>worker</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <script>
            function init(){                //创建一个Worker对象,并向它传递将在新线程中执行的脚本url
                var worker = new Worker(‘worker.js‘);                //接收worker传递过来的数据                worker.onmessage = function(event){
                    document.getElementById(‘result‘).innerHTML+=event.data+"<br/>" ;
                };
            };        </script>
    </head>
    <body onload = "init()">
        <div id="result"></div>
    </body></html>

下面是worker.js的内容:

var i = 0;function timedCount(){    for(var j = 0, sum = 0; j < 100; j++){        for(var i = 0; i < 100000000; i++){
            sum+=i;
        };
    };    //将得到的sum发送回主线程    postMessage(sum);
};//将执行timedCount前的时间,通过postMessage发送回主线程postMessage(‘Before computing, ‘+new Date());
timedCount();//结束timedCount后,将结束时间发送回主线程postMessage(‘After computing, ‘ +new Date());

上面代码执行的流程是:创建的worker对象,并用onmessage方法接收worker.js里面postMessage传递过来的数据(event.data),并将数据追加到div#result中。

所以,执行上面的代码结果如下:

 图一

待worker.js中的timedCount方法运算完后,执行postMessage操作,向主线程传数据,得图二。期间,并不影响主线程的运作。

图二

二、webWorker之常用API

接下来,再来看看关于worker的常用API:

1、postMessage(data)

子线程与主线程之间互相通信使用方法,传递的data为任意值。

//worker = new Worker(‘url‘);//worker.postMessage传递给子线程数据,对象worker.postMessage({first:1,second:2});//子线程中也可以使用postMessage,如传递字符串postMessage(‘test’);

2、terminate()

主线程中终止worker,此后无法再利用其进行消息传递。注意:一旦terminate后,无法重新启用,只能另外创建。

//worker = new Worker(‘url‘);worker.terminate();

如,主页面:

<!DOCTYPE html>
    <head>
        <title>worker</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <script>
            function init(){                var worker = new Worker(‘worker.js‘);                //每隔100毫秒,向子线程传递{name: ‘monkey‘}信息                setInterval(function(){
                    worker.postMessage({name: ‘monkey‘});
                },100);                //当主线程worker收到来自子线程的消息后,触发message事件                worker.onmessage = function(event){
                    document.getElementById(‘result‘).innerHTML+=event.data+"<br/>" ;                    //主线程使用terminate方法中断与子线程来往,在浏览器中只能显示一次event.data                    worker.terminate();
                };
            };        </script>
    </head>
    <body onload = "init()">
        <div id="result"></div>
    </body></html>

子线程worker.js代码:

//当主线程发来信息后,触发该message事件onmessage = function(event){    //向主线程发送event.data.name信息    postMessage(event.data.name);
};

3、message

当有消息发送时,触发该事件。且,消息发送是双向的,消息内容可通过data来获取。

message使用,可见terminate中的demo

4、error

出错处理。且错误消息可以通过e.message来获取。

如下:

//worker = new Worker(‘url‘);worker.onerror = function(e){    //打印出错消息    console.log(e.message);    //中断与子线程的联系    worker.terminate();
}

另:worker线程从上到下同步运行它的代码,然后进入异步阶段来对事件及计时器响应,如果worker注册了message事件处理程序,只要其有可能触发,worker就一直在内存中,不会退出,所以通信完毕后得手动在主线程中terminate或者子线程中close掉但如果worker没有监听消息,那么当所有任务执行完毕(包括计数器)后,他就会退出。

三、worker上下文

先看下面这段代码:

主页面:

<!DOCTYPE html>
    <head>
        <title>worker</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <script>
            function init(){                var worker = new Worker(‘worker.js‘);                //接收消息事件                worker.onmessage = function(event){
                    console.log(event.data);
                };                //错误信息事件                worker.onerror = function(e){
                    console.log(‘erro: ‘ + e.message);                    //终止线程                    worker.terminate();
                };
            };        </script>
    </head>
    <body onload = "init()">
        
    </body></html>

worker.js

//window对象的alert方法alert(1);
onmessage = function(event){    //向主线程发送event.data.name信息    postMessage(event.data.name);
};

执行上面代码结果:

为什么会这样呢?原因是alert为window对象的方法,所以会报错undefined。

worker.js执行的上下文,与主页面html执行时的上下文并不相同,最顶层的对象并不是window,woker.js执行的全局上下文,是个叫做WorkerGlobalScope的东东,所以无法访问window、与window相关的DOM API,但是可以与setTimeout、setInterval等协作。
WorkerGlobalScope作用域下的常用属性、方法如下:

1、self

  我们可以使用 WorkerGlobalScope 的 self 属性来或者这个对象本身的引用

2、location

  location 属性返回当线程被创建出来的时候与之关联的 WorkerLocation 对象,它表示用于初始化这个工作线程的脚步资源的绝对 URL,即使页面被多次重定向后,这个 URL 资源位置也不会改变。

3、close

  关闭当前线程,与terminate作用类似

4、importScripts

  我们可以通过importScripts()方法通过url在worker中加载库函数

5、XMLHttpRequest

  有了它,才能发出Ajax请求

6、setTimeout/setInterval以及addEventListener/postMessage

四、关于worker

我们可以做什么:

  1.可以加载一个JS进行大量的复杂计算而不挂起主进程,并通过postMessage,onmessage进行通信

  2.可以在worker中通过importScripts(url)加载另外的脚本文件

  3.可以使用 setTimeout(), clearTimeout(), setInterval(), and clearInterval()

  4.可以使用XMLHttpRequest来发送请求

  5.可以访问navigator的部分属性

局限性:

  1.不能跨域加载JS

  2.worker内代码不能访问DOM

  3.各个浏览器对Worker的实现不大一致,例如FF里允许worker中创建新的worker,而Chrome中就不行

  4.IE这个新特性

时间: 2024-12-27 21:38:47

浅谈webWorker的相关文章

浅谈浏览器的缓存机制

浏览器的缓存可分为HTTP缓存和离线缓存,下面将分别介绍 HTTP缓存 只有GET请求能被缓存,POST不能被缓存.Modified Time/ETag/Expires/Cache都是HTTP协议的缓存策略 先来一个例子 当我们第二次访问百度首页,在Chrome的Network面板中打开一个静态文件时会发现响应的status是:200 OK (from disk cache),不是应该返回304 Not Modified吗?如果你知道答案,那就可以忽略本文了. Cache-Control 简介

.net中对象序列化技术浅谈

.net中对象序列化技术浅谈 2009-03-11 阅读2756评论2 序列化是将对象状态转换为可保持或传输的格式的过程.与序列化相对的是反序列化,它将流转换为对象.这两个过程结合起来,可以轻松地存储和传输数 据.例如,可以序列化一个对象,然后使用 HTTP 通过 Internet 在客户端和服务器之间传输该对象.反之,反序列化根据流重新构造对象.此外还可以将对象序列化后保存到本地,再次运行的时候可以从本地文件 中“恢复”对象到序列化之前的状态.在.net中有提供了几种序列化的方式:二进制序列化

浅谈——页面静态化

现在互联网发展越来越迅速,对网站的性能要求越来越高,也就是如何应对高并发量.像12306需要应付上亿人同时来抢票,淘宝双十一--所以,如何提高网站的性能,是做网站都需要考虑的. 首先网站性能优化的方面有很多:1,使用缓存,最传统的一级二级缓存:2,将服务和数据库分开,使用不同的服务器,分工更加明确,效率更加高:3,分布式,提供多台服务器,利用反向代理服务器nginx进行反向代理,将请求分散开来:4,数据库的读写分离,不同的数据库,将读操作和写操作分开,并实时同步即可:5,分布式缓存,使用memc

单页应用SEO浅谈

单页应用SEO浅谈 前言 单页应用(Single Page Application)越来越受web开发者欢迎,单页应用的体验可以模拟原生应用,一次开发,多端兼容.单页应用并不是一个全新发明的技术,而是随着互联网的发展,满足用户体验的一种综合技术. SEO 一直以来,搜索引擎优化(SEO)是开发者容易忽略的部分.SEO是针对搜索(Google.百度.雅虎搜索等)在技术细节上的优化,例如语义.搜索关键词与内容相关性.收录量.搜索排名等.SEO也是同行.市场竞争常用的的营销手段.Google.百度的搜

浅谈html标签

浅谈html各常用标签用法 标题标签:<h1>-<h6>来表示,使标题字体变粗. <br />换行标记 <hr />水平分隔符 &nbsp空格符 &copy版权符 <a href>a标签超链接 href可接链接地址 <p>段落标签<blockquote>引用标签及可用做缩进 <table>表格中的<ul>无序列表<ol>有序列表<dl>自定义列表<row

浅谈二维中的树状数组与线段树

一般来说,树状数组可以实现的东西线段树均可胜任,实际应用中也是如此.但是在二维中,线段树的操作变得太过复杂,更新子矩阵时第一维的lazy标记更是麻烦到不行. 但是树状数组在某些询问中又无法胜任,如最值等不符合区间减法的询问.此时就需要根据线段树与树状数组的优缺点来选择了. 做一下基本操作的对比,如下图. 因为线段树为自上向下更新,从而可以使用lazy标记使得矩阵的更新变的高校起来,几个不足就是代码长,代码长和代码长. 对于将将矩阵内元素变为某个值,因为树状数组自下向上更新,且要满足区间加法等限制

[nRF51822] 14、浅谈蓝牙低功耗(BLE)的几种常见的应用场景及架构(科普类干货)

蓝牙在短距离无线通信领域占据举足轻重的地位—— 从手机.平板.PC到车载设备, 到耳机.游戏手柄.音响.电视, 再到手环.电子秤.智能医疗器械(血糖仪.数字血压计.血气计.数字脉搏/心率监视器.数字体温计.耳温枪.皮肤水分计等), 再到智能家居等领域均占有一席之地. 而蓝牙低功耗(BLE)是在蓝牙4.0协议上修改以适用低功耗应用场景的一种蓝牙协议. 随着上一股智能消费类电子大潮的到来,BLE的各种应用也像雨后春笋般在市场上铺开. 如果想 紧跟蓝牙协议的最新动态 ,可以在https://www.b

浅谈C++容器动态内存管理的优化

在信息学竞赛中,C++的容器的用途非常广泛,但经常因常数过大而超时.怎样才能提高它们的效率呢? 我们知道,容器是存储同一类对象的对象,既然"对象"我们无法改变,那么我们只能从"存储"入手,不难想到,不同容器在实现上的根本区别是它们对应着不同的内存组织方式,内存管理无疑是这种实现的核心,所以优化内存管理是加快容器效率的最好途径之一. 一.内存分配器简介 怎样才能优化内存管理呢?很简单,C++为我们提供了这样的接口,我们可以通过自定义容器模板中的最后一个allocato

张小龙浅谈微信公众平台的意义

腾讯高级副总裁张小龙表示:微信公众平台,就是在移动互联网时代,让企业和个人以更简捷的形式提供服务给有需要的人. 张小龙浅谈微信公众平台的意义,布布扣,bubuko.com