前言


前端工程师们一定有过这样的体验,当一个页面加载了大量的 js 文件时,用户界面可能会短暂地“冻结”。这很好理解,因为 js 是单线程的语言。我们再走的极端点,一段 js 中出现了 while(){} 的死循环,这时再去点击页面的 DOM 元素,将不会触发事件,事实上,这些异步的事件都排成了队列,只等页面的 js 渲染完后去执行(从setTimeout谈JavaScript运行机制),而此时渲染进入了死循环,所以出现了用户界面被“冻结”的现象。

而实际的开发中,虽然不会出现类似的死循环,但是大量的 js 渲染还是会影响用户体验的,此时我们希望这段耗时的 js 最好能异步去执行,setTimeout 是一个好的方法,但是 H5 提供了更好的办法,Web Worker! Web Worker 规范通过让 Javascript 在后台运行解决了这个问题。浏览器实现 Web Worker 规范的方式有很多种,可以使用线程、后台进程或者运行在其他处理器核心上的进程,等等。具体的实现细节其实没有那么重要,重要的是开发人员现在可以放心地运行 Javascript,而不必担心会影响用户体验了。

既然 Worker 是 H5 大家庭的,那么 ie6 之辈就可以一边去了,详细的浏览器兼容性可以参考 http://caniuse.com/#search=worker

如果没有 Worker


我们来看这样一段代码:

<div style='width:100px;height:100px;background-color:red'></div>
<script>
  document.querySelector('div').onclick = function() {
    console.log('hello world');
  };

  function fibonacci(n) {
    return n < 2 ? n : arguments.callee(n - 1) + arguments.callee(n - 2);
  }

  console.log(fibonacci(36));
</script>

页面上写了一个 div,然后监听了它的 click 事件,并且在 js 中需要计算斐波那契数列的第 36 项,并将它输出。这样的页面用户体验是非常差的,如果 fibonacci 不执行完,div 的 click 事件是无法及时响应的,而递归求解斐波那契数列项是相当耗时的!这样一段耗时的 js 代码,交给 worker 来做正合适!

祭出大杀器 Worker


Worker 的使用方法很简单。

实例化 Worker 对象并传入要执行的 Javascript 文件名就可以创建一个新的 Web Worker:

var worker = new Worker('worker.js');

这段代码会导致浏览器下载 worker.js,但只有 Worker 接收到消息才会实际执行文件中的代码。要给 Worker 传递消息,可以使用 postMessage() 方法,比如我要告诉 Worker 需要求斐波那契数列的第 36 项:

worker.postMessage(36);

我们来看看 Worker 是怎么接收消息的。当页面在 worker 对象上调用 postMessage()时,数据会以异步方式传递给 worker,进而触发 worker 中的 message 事件。为了处理来自页面的数据,同样也要创建一个 onmessage 事件处理程序。(worker.js 代码)

self.onmessage = function(event) {
  var data = event.data;
  console.log(fibonacci(data));
};

function fibonacci(n) {
  return n < 2 ? n : arguments.callee(n - 1) + arguments.callee(n - 2);
}

页面可以传数据给 Worker,Worker 当然也可以回传,页面通过 message 事件进行监听:

worker.onmessage = function(event) {
  var data = event.data;
};

Worker 是通过 message 和 error 事件与页面通信的。来自 Worker 的数据保存在 event.data 中。Worker 不能完成给定的任务时会触发 error 事件。具体来说,Worker 内部的 Javascript 在执行过程中只要遇到错误,就会触发 error 事件。发生 error 事件时,事件对象中包含三个属性:filename、lineno 和 message,分别表示错误的文件名、代码行号和完整的错误信息:

worker.onerror = function(event) {
  console.log(event.filename, event.lineno, event.message);
};

我们建议使用 worker 时最好写上 error 事件,就像使用 ajax 时总要写上获取失败时的补救操作一样。

完整代码:

html 文件:

<div style='width:100px;height:100px;background-color:red'></div>
<script>
  document.querySelector('div').onclick = function() {
    console.log('hello world');
  };

  var worker = new Worker('worker.js');
  worker.postMessage(36);
  worker.onmessage = function(event) {
    var data = event.data;
    console.log(data)
  };

  worker.onerror = function(event) {
    console.log(event.filename, event.lineno, event.message);
  };
</script>

worker.js 文件:

self.onmessage = function(event) {
  var data = event.data;
  var ans = fibonacci(data);
  this.postMessage(ans);
};

function fibonacci(n) {
  return n < 2 ? n : arguments.callee(n - 1) + arguments.callee(n - 2);
}

简单小结:

WEB主线程:

  1. 通过 var worker = new Worker(url) 加载一个 js 文件来创建一个 worker,同时返回一个 worker 实例。
  2. 通过 worker.postMessage(data) 方法来向 worker 发送数据。
  3. 绑定 worker.onmessage 方法来接收 worker 发送过来的数据。
  4. 可以使用 worker.terminate() 来终止一个 worker 的执行。

worker新线程:

  1. 绑定 onmessage 方法来接收主线程发送过来的数据。
  2. 通过 postMessage(data) 方法来向主线程发送数据。
  3. 可以使用 self.close() 来终止一个 worker 的执行。

Worker 其他


关于 Web Worker,最重要的是要知道它所执行的 Javascript 代码完全在另一个作用域中,与当前网页中的代码不共享作用域。在 Web Worker 中,同样有一个全局对象(worker 对象本身,this 和 self 引用的都是 worker 对象本身)和其他对象以及方法。Web Worker 中的代码不能访问 DOM。那么 Worker 里的代码能访问哪些对象,拥有哪些方法?

  1. 最小化 的navigator 对象,包括 onLine、appName、appVersion、userAgent 和 platform 属性
  2. 只读的 location 对象
  3. setTimeout()、setInterval()、clearTimeout()、clearInterval() 方法
  4. XMLHttpRequest 构造函数

任何时候都能中止 Worker。在 worker.js 中,我们可以用 self.close()方法,而在页面中,我们可以用 worker.terminal()方法,这时 error 和 message 事件也不会触发了。

Web Worker 是什么鬼?的更多相关文章

  1. JavaScript多线程之HTML5 Web Worker

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

  2. Web Worker javascript多线程编程(一)

    什么是Web Worker? web worker 是运行在后台的 JavaScript,不占用浏览器自身线程,独立于其他脚本,可以提高应用的总体性能,并且提升用户体验. 一般来说Javascript ...

  3. Web Worker javascript多线程编程(二)

    Web Worker javascript多线程编程(一)中提到有两种Web Worker:专用线程dedicated web worker,以及共享线程shared web worker.不过主要讲 ...

  4. 过段时间逐步使用HTML5新增的web worker等内容

    想来快2017年了,2013年前的手机应该很少有人用了,以后逐渐使用HTML5新增的高级API吧. 先把web worker的内容再熟悉一下,因为微软虚拟学院的'面向有经验开发人员的 JavaScri ...

  5. web Worker使js实现‘多线程’?

    大家都知道js是单线程的,在上一段js执行结束之前,后面的js绝对不会执行,那么为什么标题说js实现‘多线程’,虽然说加了引号,可是标题也不能乱写不是,可恶的标题党? 姑且抛开标题不说,先说我们经常会 ...

  6. HTML5:web socket 和 web worker

    a:hover { cursor: pointer } 做练习遇到了一个选择题,是关于web worker的,问web worker会不会影响页面性能?补习功课之后,答案是不会影响. 查阅了相关资料学 ...

  7. javascript 多线程Web Worker不引用外部js文件的方法

    最近在Android开发中 Webview通过调用JavascriptInterface的方式与App交互 在交互的过程中,有些App上的操作时间会比较长,Web中调用的话会造成程序假死的情况 于是想 ...

  8. HTML5 Web Worker的使用

    Web Workers 是 HTML5 提供的一个javascript多线程解决方案,我们可以将一些大计算量的代码交由web Worker运行而不冻结用户界面. 一:如何使用Worker Web Wo ...

  9. Web Worker

    写在前面 众所周知,JavaScript是单线程的,JS和UI更新共享同一个进程的部分原因是它们之间互访频繁,但由于共享同一个进程也就会造成js代码在运行的时候用户点击界面元素而没有任何响应这样的情况 ...

随机推荐

  1. SVN安装使用小结

    SVN在实际的项目开发中有很广泛的用途.一开始接触SVN(Subversion),思路并不清楚,现在总算理清了. 声明:本文并不是系统地对SVN做介绍,而是笔者的使用总结,个人认为的一些要点,可能对初 ...

  2. 安卓+servlet+MySql 查询+插入(汉字乱码解决)

    问题: 安卓程序,通过servlet连接MySQL数据库,并实现查询和插入(修改,删除类似). 其中遇到的最大的问题是:汉字乱码问题(查询条件有汉字乱码.servlet的汉字到数据乱码.安卓通过ser ...

  3. Git中文版教程

    1. 起步 1.1 关于版本控制 1.2 Git 简史 1.3 Git 基础 1.4 命令行 1.5 安装 Git 1.6 初次运行 Git 前的配置 1.7 获取帮助 1.8 总结 2. Git 基 ...

  4. u盘安装CENTOS后,启动missing operating system ,只能用U盘才能启动系统

    好久之前就想把家里闲置的那台老的不能再老的笔记本换成linux的,用来学习 从N久之前用光盘安装的时候发现光驱坏掉了之后就没有再装过,最近又想安装于是就试了U盘安装 U盘安装过程也很简单,只需要制作一 ...

  5. easyui datagrid 键盘上下控制选中行

    扩展datagrid的一个方法keyCtr $.extend($.fn.datagrid.methods, { keyCtr : function (jq) {  return jq.each(fun ...

  6. cat,tac,more

    cat VS tac cat是查看文本文件的内容,tac是cat反过来,反向查看文件 $cat 1.txt ls: cannot access ee: No such file or director ...

  7. WIN 程序员的 Linux 互斥类

    作者:黄山松,发表于cnblogs:http://www.cnblogs.com/tomview/ 对于一个 win 的程序员,要把在 win 下的程序移植到 linux 下,需要把一些平台相关的功能 ...

  8. 父容器根据子容器高度自适应:设置父容器 height:100%;overflow:hidden;

    父容器根据子容器高度自适应:设置父容器  height:100%;overflow:hidden;

  9. C++/C#互调步骤

    一.C#调用C++ dll步骤(只能导出方法):  * 1. c++建立空项目->源文件文件夹中添加cpp文件和函数  * 2. c++属性设置中,配置类型设置为动态库dll,公共语言运行时支持 ...

  10. windows 10 & Office 2016 安装

    Office 2016 VOL版    http://blog.sina.com.cn/s/blog_470614a90102vtmc.html 专业版合集: magnet:?xt=urn:btih: ...