HTML5之Web Workers多线程的使用与不足

什么是Web Worker ?

当HTML页面中执行JS时,页面的状态是不可响应的,直到脚本已完成。
Web Worker是运行在后台的JavaScript,独立于其它脚本,不会影响页面的性能。您可以继续继续做任何想做的事情:点击、选取内容等,而此时web worker在后台运行。

在学习Web Worker前,我们先举个例子看看执行复杂的JS时,是不是会影响页面性能。
封装一个函数实现斐波那契数列:数学公式:F(n)=F(n-1)+F(n-1);即当前值等于前两个值之和。

代码示例:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Web Worker</title>
  </head>
  <body>
    <input type="text" id="number" />
    <button id="button">计算</button>
    <script>
      function fibonacci(n) {
     
     
        return n <= 2 ? 1 : fibonacci(n - 1) + fibonacci(n - 2)
      }
      var button = document.querySelector('#button')
      button.onclick = function () {
     
     
        var input = document.querySelector('#number')
        var result = fibonacci(input.value)
        alert(result)
      }
    </script>
  </body>
</html>

在这里插入图片描述
上面是gif格式的动图,你会发现当点击‘计算’按钮后并不是立即弹出结果,而是有个短暂时间才弹出来。这是因为这是一段递归计算的代码,即函数不断进入栈中执行。由于JS是单线程的,而且UI界面的渲染交互都是主线程的工作,那么在fibonacci函数执行完前都占用了主线程,那么此时我们点击页面是无法进行任何交互的,这给用户很差的体验。

由于JS是单线程的,无法解决该问题,但HTML5提供了Web Worker是一个JavaScript多线程解决方案。

我们可以将一些大计算量的代码交由web Worker运行而不冻结用户界面。

下面开始使用web worker:

创建一个work.js文件,它将在分线程执行:

function fibonacci(n) {
    
    
  return n <= 2 ? 1 : fibonacci(n - 1) + fibonacci(n - 2)
}

var onmessage = function (event) {
    
    
  let value = event.data //从event中获取主线程传来的数据
  let result = fibonacci(value)
  postMessage(result) //向主线程返回计算结果
}

修改HTML的代码:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Web Worker</title>
  </head>
  <body>
    <input type="text" id="number" />
    <button id="button">计算</button>
    <script>
      var button = document.querySelector('#button')
      button.onclick = function () {
     
     
        let input = document.querySelector('#number')
        let value = input.value
        let worker = new Worker('./worker.js')//参数是work.js文件的路径
        worker.postMessage(value) //向worker.js发送数据
        worker.onmessage = function (event) {
     
     
          alert(event.data)
          console.log(event)
        }
      }
    </script>
  </body>
</html>

虽然使用web worker不会加快该函数的计算速度,但是主线程可以做其它事情。我们打印了event,看看属性:
在这里插入图片描述
event中的data属性就是返回的数据。web worker用法很简单,使用 postMessage发送数据,onmessage监听并通过event接收数据。
主线程与分线程都有消息队列和EventLoop:
在这里插入图片描述

web worker虽好,但是也有一些缺点:

  • 浏览器兼容性差
  • worker内不能访问DOM,即不能更新UI
  • 不能跨域加载JS

我们看看为什么worker.js内不能访问DOM?

在html文件中默认的全局对象是window,所以我们能通过document.getXXX()等方法获取DOM元素;但是在worker.js文件中默认的全局对象,也就是this指针的指向不再是window,而是worker对象,所以我们在worker.js中根本获取不到DOM,所以也就操作不了DOM更新不了UI。

在worker.js打印this指针:
在这里插入图片描述
正是worker.js中的this自动指向了worker对象,所以我们才能直接使用postMessage等方法。

猜你喜欢

转载自blog.csdn.net/weixin_43334673/article/details/109646776
今日推荐