了解web Worker实现多线程工作

分类:前端来源:站内 最近更新:2020-10-07 11:20:10浏览:112留言:0

了解web Worker实现多线程工作

概述

   

     Js是单线程的,也就是任务得一件件的按照顺序处理,前面的任务没有处理完成,后面的只能等着。但是随着科技的发展,现在的计算机都是多核的CPU,单线程无法发挥计算机的能力。

    Web Worker 的作用就是在js主线程上创建一个辅助线程(Worker线程),将一些任务分配给Worker线程运行。两个线程互不干扰,也能相互通信。用户在主线程上进行UI交互时,不会卡顿和阻塞。Worker 线程也不会因为主线程交互而被打断。这个和之前的Service Worker很类似

    注意,Worker 线程比较耗费资源,不应该过度使用,任务完成后要关闭。同时,Web Worker 有以下几个使用注意点:

  • 同源限制,执行Worker线程的脚步文件必须和主线程在一个host下

  • DOM限制,Worker线程不能操作document,window,parent等对象,但可以操作navigator和location对象

  • 脚本限制,Worker 线程不能执行aler()和confirm()方法,但可以使用XMLHttpRequest 对象发出 AJAX 请求。

  • 引用路径,Worker 线程引用文件时,必须是同源下的相对或者绝对路径。

  • 上下文环境,Worker线程和主线程不在同一个上下文环境,他们之间通过xx.postMessage相互通信。

  • 通信数据独立,主线程和Worker线程传递的数据都是独立的,通信的数据都是先转字符串再还原的过程,所以不用担心对象深拷贝的问题


用法


主线程

1、在主线程上新建worker线程

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

    构造函数Worker引用的脚步文件work.js就是Worker线程的执行任务。如果构造函数Worker引用的参数路径不对,Worker会默认失败,Worker线程将不执行。


2、主线程给Woker线程发消息

worker.postMessage('Hello World');
worker.postMessage({method: 'echo', args: ['Work']});

    主线程通过实例对象worker的postMessage向Worker发消息。postMessage的参数可以是任意类型。


3、主线程监听Woker线程发消息

worker.onmessage = function (event) {
  console.log('Received message ' + event.data);
  doSomething();
}
function doSomething() {
  // 执行任务
  worker.postMessage('Work done!');
}

    主线程通过调用实例onmessage方法监听Worker线程发来的消息(event.data)


4、主线程关闭Woker线程

worker.terminate();


Worker线程

1、Worker线程监听主线程消息

self.addEventListener('message', function (e) {
  self.postMessage('You said: ' + e.data);
}, false);

    self代表Woker线程的全局对象,等同下面两种写法:

// 写法一
this.addEventListener('message', function (e) {
  this.postMessage('You said: ' + e.data);
}, false);

// 写法二
addEventListener('message', function (e) {
  postMessage('You said: ' + e.data);
}, false);


2、Worker线程给主线程发送消息

self.addEventListener('message', function (e) {
  var data = e.data;
  switch (data.cmd) {
    case 'start':
      self.postMessage('WORKER STARTED: ' + data.msg);
      break;
    case 'stop':
      self.postMessage('WORKER STOPPED: ' + data.msg);
      self.close(); // Terminates the worker.
      break;
    default:
      self.postMessage('Unknown command: ' + data.msg);
  };
}, false);

    和主线程方法一样,通过调用Worker线程的postMessage向主线程发送消息,参数就是发送的数据


3、Worker线程关闭自身

self.close();


拓展

1、可以在同一个文件里编写主线程和worker线程。

<!DOCTYPE html>
  <body>
  //worker线程的脚本
    <script id="worker" type="app/worker">
      addEventListener('message', function () {
        postMessage('some message');
      }, false);
    </script>
    //主线程脚本
    <script>
        var blob = new Blob([document.querySelector('#worker').textContent]);
            var url = window.URL.createObjectURL(blob);
            var worker = new Worker(url);
            worker.onmessage = function (e) {
              // e.data === 'some message'
            };
    </script>
  </body>
</html>

    上面代码中,先将嵌入网页的脚本代码,转成一个二进制对象,然后为这个二进制对象生成 URL,再让 Worker 加载这个 URL。这样就做到了,主线程和 Worker 的代码都在同一个网页上面。


API

Worker()

var myWorker = new Worker(jsUrl, options);

    主线程全局对象提供了Worker构造函数,它接收两个参数,第一个参数是脚本文件的的同源网址,该参数必须的,否则会报错;第二个参数是可选的配置对象,它的主要作用是指定Worke线程的名称,用来区分多个Worker线程。


// 主线程

var myWorker = new Worker('worker.js', { name : 'myWorker' });


// Worker 线程

self.name // myWorker

Worker()创建的实例对象,提供了以下属性和方法:

  • Worker.onerror:指定 error 事件的监听函数。

  • Worker.onmessage:指定 message 事件的监听函数,发送过来的数据在Event.data属性中。

  • Worker.onmessageerror:指定 messageerror 事件的监听函数。发送的数据无法序列化成字符串时,会触发这个事件。

  • Worker.postMessage():向 Worker 线程发送消息。

  • Worker.terminate():立即终止 Worker 线程。


Web Worker 有自己的全局对象,不是主线程的window,而是一个专门为 Worker 定制的全局对象。因此定义在window上面的对象和方法不是全部都可以使用。

Worker 线程有一些自己的全局属性和方法。

  • self.name: Worker 的名字。该属性只读,由构造函数指定。

  • self.onmessage:指定message事件的监听函数。

  • self.onmessageerror:指定 messageerror 事件的监听函数。发送的数据无法序列化成字符串时,会触发这个事件。

  • self.close():关闭 Worker 线程。

  • self.postMessage():向产生这个 Worker 线程发送消息。

  • self.importScripts():加载 JS 脚本。


兼容性

Dingtalk_20201007104922.jpg

0

发表评论

评论列表(0)

  • 暂时没有留言
热门