WebWorker异步处理

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WebWorker异步处理相关的知识,希望对你有一定的参考价值。

参考技术A HTML5的时代来到了,由于前端负责的数据处理越来越大,单单靠一个JS的单线程越来越力不从心,webWorker的出现能更好的解决该问题,这篇文章将讲述webWorker的使用。

使用webWorker我们可以将一些大量计算的事情放置在另一个线程进行处理,这时候我们页面不会被卡死,让网页使用流畅。

比如我们进行一个50亿次的加法计算。

在我的电脑上是2秒多,但一般的电脑可能要慢很多,但是作为页面展示如果需要2秒的时间那么用户体验将是相当不好的,因为两秒种的时间用户都无法操作。

这时候一般只能使用 setTimeout 将计算拆除,或者请求服务器处理,但是都很麻烦,在这里我们使用 Worker 就可以了。

script of html

worker-5x10^9.js

使用webWorker可以避免大量的计算导致的拥塞,避免页面假死,充分利用客户端的物理资源。

下面我们来详细讲述如何使用 webWorker 。

虽然作为HTM5的新特性,但是各大浏览器对 webWorker 的支持都是很好的,所以我们基本可以大胆的尝试在工程中使用。

webWorker 在浏览器中的构造函数为 Worker()

但是必须传入一个字符串参数作为 webWorker 运行的内容,在上面的示例中便是传入了 worker-5x10^9.js 来让其执行。

我们可以看看输出worker实例对象。

我们可以看到它主要包含4个方法:

十分简单

这个方法是在Worker的error事件触发时执行,需要给onerror赋值一个函数,并且会给该函数传递一个事件对象。

script of html

worker-error.js

这样我们就可以获取到内部的错误信息,并加以处理,但是一般对这方面的需求很少,主要获取内部运行的情况。

这个方法是在Worker的内部执行 postMessage 事件触发时执行,需要给onmessage赋值一个函数,并且会给该函数传递一个事件对象。传递的值通过事件对象的 data 属性获取。

script of html

worker-postMessage.js

这样我们就可以获取到内部的发出信息。

这个方法是向Worker的内部发送消息,在这里不止是传递字符串,可以传递对象等,但是不能传递函数包含的对象。

他会对对象进行深度克隆,所以可以用来进行对象的异步的深度克隆。这一部分在下面进行详细阐述。

script of html

worker-postMessage.js

由于执行是异步的,所以还是要主线程的JS执行完毕后才能执行对事件的响应,第一个错误是因为对有函数的对象解析导致的,所以我们只能看到前面两个的字付串输出。

这个函数是立刻停止worker的运行,不会等待worker的运行完成。

script of html

我们可以看到这里只有 123 输出,虽然依然可以向worker发送消息,但是没什么卵用。

worker的执行的环境和浏览器环境的有一些不同,浏览器内全局变量是 window 而 worker内部是 DedicatedWorkerGlobalScope

在这个环境中无法使用window来获取全局变量

script of html

worker-window.js

我们可以看到window是没有定义的,想要获取我们需要使用 self

worker-self.js

这样我们就可以获取内部的全局变量了,其实self在浏览器环境下也是指向全局环境的。

worker的内部环境当然也和浏览器下的环境差不多,都含有相关的全局方法。

worker的内部环境也是支持console.log来方便调试的,并且它的输出会展示在浏览器的控制台当中

worker-self.js

这两个对象都是支持的,所以webWorker,可以负责数据请求的收发。

worker内部是无法操作DOM的,主要是为了线程安全,但是我们在采用VDOM的时候,便可以放入worker内部处理VDOM。

在worker的postMessage方法,已经worker内部的postMessage都是支持对象传递的,它可以传递满足 The structured clone algorithm | 结构化克隆算法 的对象。

script of html

worker-transferList.js

同时在深复制的时候还保持了内部的索引结构。

最难弄清的其实是 postMessage 的 transferList 参数。

transferList数组类型必须为 ArrayBuffer , MessagePort and ImageBitmap

我们设置成 ArrayBuffer

我们可以看到post成功了,但同时我们会发现bufArr.byteLength的长度改变了,因为byteLength的上下文已经搬移到worker内部了。

script of html

worker-transferList.js

上述讲述的都是页面独享 Worker 也叫 DedicatedWorker ,然而还有一个 SharedWorker 。

DedicatedWorker 会在页面关闭时随之关闭,而 SharedWorker 会在所有关联的页面都关闭后才关闭。

shared.js

worker-shared.js

当我们只在第一个页面进行刷新时,输出的都是0,但当有两个页面时,刷新一个页面输出的内容就不再只是0。

当只有一个页面时

当有两个页面时

这里 webWorker 简单的介绍就算完了,使用 webWorker 能减少页面的拥塞,充分利用客户的物理资源处理大量数据同时还可以用于封装接口层,毕竟是支持AJAX和webSocket的~~~。

MDN_Worker

caniuse_Worker

(转载)WebWorker是什么鬼?

前言

前端工程师们一定有过这样的体验,当一个页面加载了大量的 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 事件也不会触发了。

参考文献:http://mdsa.51cto.com/art/201511/497002.htm

以上是关于WebWorker异步处理的主要内容,如果未能解决你的问题,请参考以下文章

WebAssembly是什么?

让你的Javascript计算性能提升70%

JS异步那些事 四(HTML 5 Web Workers)

架构设计 | 异步处理流程,多种实现模式详解

JavaScript异步处理问题,循环处理异步任务,并拿到数据,Nodejs循环异步任务接口处理

求一个异步处理消息的方法