• Web Worker 是什么鬼?


    前言


    前端工程师们一定有过这样的体验,当一个页面加载了大量的 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='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 时总要写上获取失败时的补救操作一样。

    完整代码(运行 demo 必须起个本地服务):

    html 文件:

    <div style='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 事件也不会触发了。

  • 相关阅读:
    GridView中checkbox实现全选[转]
    go 格式化秒 running
    mysql 聚簇索引和非聚簇索引 running
    go context上下文取消 running
    go reflect running
    time.ticker running
    go 数据结构与算法之二分查找 running
    mysql 联合索引最左前缀匹配原则 running
    es 修改 mapping 字段类型 running
    linux 查看虚拟机网卡命令 running
  • 原文地址:https://www.cnblogs.com/lessfish/p/4954328.html
Copyright © 2020-2023  润新知