一、前言
??在html5出来以后,有许多新特性值得我们关注, 其中一个就是web worker。相信如果关心前端发展的同学就算没有使用过web worker也听过这个东西。今天我们就来讲一讲web worker。
二、基本使用
??其实,web worker的作用十分简单,就是可以在后台运行一个js文件,所以我们在实际使用中可以将一些非常耗时的计算交给web worker去做。但是值得注意的是,在web worker中是无法拿到window/document/parent对象的,以我的理解就是,你可以看作是与该页面完全独立的一个线程。所以如果涉及到大量的dom操作的时候我们是无法靠web worker完成的,相反,如果是大量的计算工作,我们完全可以将其交给web worker来做,最后将计算的结果返回给我们。说了这么多,那么我们下面来实际使用一下。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body><p>计数: <output id="result"></output></p>
<button onclick="startWorker()">开始工作</button>
<button onclick="stopWorker()">停止工作</button><script>var w;function startWorker() {
w = new Worker('./index.js');w.onmessage = function(event) {
document.getElementById('result').innerHTML = event.data;}}function stopWorker() {
w.terminate();} </script></body>
</html>
我们创建一个worker对象, 将一个js文件作为参数传递给它。注意,worker不接受file对象,所以我们需要在本地搭一个简单的服务器来运行这个例子。下面的index.js中的内容
var i=0;function timedCount()
{
i=i+1;postMessage(i);setTimeout("timedCount()",500);
}timedCount();
我们点击开始工作以后,index.js就会在后台运行,然后通过postMessage给主线程传递数据。而我们通过onmessage来指点监听函数,获取子线程传递回来的数据,并显示到页面上。更加具体的教程可以参考阮一峰的博客。
三、深入思考
??你看完这个例子之后是不是会觉得这玩意非常简单,对,是非常简单。那么我们再来实践一下。我们之前的延迟时间是500ms,我们现在想变成1000ms。那简单,我们去index.js中把代码改一下。但是如果在实际生产中,我们只能运行一个写死的js文件,那我觉得这个东西是毫无意义的,所以我们需要想办法动态创建一个js文件,然后交给webworker去执行。
四、动态创建Web Worker
??不熟悉Blob对象和URL.createObjectURL的同学可以先去搜一下他们的概念以及使用方式,这里我们就用它们来实现我们想要的效果。话不多说,我们直接上代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body><script>function demo() {
console.log('isok');}let blob = new Blob([demo.toString() + ' demo()'], {
type: 'text/javascript'});let worker = new Worker(URL.createObjectURL(blob));
</script></body>
</html>
这里我们先定义了一个demo函数,这就是我们后面想要运行的函数。随后将这个函数作为参数传新建一个blob对象。在将blob对象作为createObjectURL的参数,最后将结果作为web worker的参数。打开页面后,我们来看看控制台的输出:
nice!我们已经动态创建了一个函数并用web worker去运行他,下一步我们将其封装成一个函数,方便我们调用。
class MyWorker {
constructor(f, cb) {
this.f = f;this.worker = null;this.onemessage = cb;}start() {
const blob = new Blob([`${
this.f.toString()} ${
this.f.name}()`], {
type: 'text/javascript'});const url = URL.createObjectURL(blob);this.worker = new Worker(url);this.worker.onmessage = (event) => this.onemessage(event.data)}end() {
this.worker.terminate();}
}
我们定义一个MyWorker,传递的参数是要执行的函数和接受参数的函数,这样我们就可以在外部定义一个函数,然后将其作为参数传给worker,实现一个动态的web worker。我们来看看效果:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><script src="./MyWorker.js"></script><title>Document</title>
</head>
<body><script>function demo() {
var i = 0;function f() {
postMessage(i);i++;setTimeout(f, 500);}f();}let worker = new MyWorker(demo, function(data) {
console.log(data)});worker.start();setTimeout(() => worker.end(), 2000)</script>
</body>
</html>
可以看到这就是我们想要的结果。
五、结语
??本篇文章只是为如何创建一个动态的web worker提供了一个思路,可以看到,我们通过blob和URL.createObjectURL就可以动态创建一个web worker,这比我们直接运行一个写死的文件要灵活许多。同时对我而言我目前还没有遇见web worker的实际应用场景,等自己什么时候遇见了需要动态使用web worker使用的应用场景,再来对其进行一个比较透彻的研究。