基于blob对象动态封装一个web worker

一、前言

  在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使用的应用场景,再来对其进行一个比较透彻的研究。

发布了24 篇原创文章 · 获赞 46 · 访问量 5146

猜你喜欢

转载自blog.csdn.net/qq_38164763/article/details/99708144