webworker - api限制

177 阅读3分钟

Web worker是html5引入的新特性,它允许开发者在浏览器后台运行脚本,从而使得主线程(通常负责UI交互)能够在不被阻塞的情况下运行。

Web Worker环境与主线程有一些不同,因此在Web Worker中使用某些API时会有一些限制。了解这些限制有助于功能的设计和开发。以下是一些常见的API限制及说明:

1、DOM访问限制

不能直接访问DOM

2、Window对象限制

不能访问window对象

3、本地存储限制

不能访问localStorage和sessionStorage

4、可以访问IndexDB

5、XMLHttpRequest(XHR)和Fetch API

6、Canvas 2D和WebGL

7、Web Audio API

可以使用 Web Audio API 进行音频处理

8、WebSocket

支持websocket用于实时通信

9、事件循环

Web Worker有自己的事件循环,用于处理定时任务,网络请求等

10、导入脚本

Web Worker可以使用importScripts方法导入其他的脚本文件

示例:

// mathHelper.js 辅助文件
function add(a, b) {
  return a + b;
}

function subtract(a, b) {
  return a - b;
}

function multiply(a, b) {
  return a * b;
}

function divide(a, b) {
  if (b !== 0) {
    return a / b;
  } else {
    throw new Error('Division by zero');
  }
}

// worker.js  webworker脚本文件
importScripts('mathHelper.js');

self.onmessage = function(event) {
  const { operation, a, b } = event.data;

  try {
    let result;
    switch (operation) {
      case 'add':
        result = add(a, b);
        break;
      case 'subtract':
        result = subtract(a, b);
        break;
      case 'multiply':
        result = multiply(a, b);
        break;
      case 'divide':
        result = divide(a, b);
        break;
      default:
        throw new Error('Unknown operation');
    }
    self.postMessage({ result });
  } catch (error) {
    self.postMessage({ error: error.message });
  }
};

// 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 Example</title>
</head>
<body>
  <label for="operation">Operation:</label>
  <select id="operation">
    <option value="add">Add</option>
    <option value="subtract">Subtract</option>
    <option value="multiply">Multiply</option>
    <option value="divide">Divide</option>
  </select>
  <br>
  <label for="a">Number A:</label>
  <input type="number" id="a" value="10">
  <br>
  <label for="b">Number B:</label>
  <input type="number" id="b" value="5">
  <br>
  <button id="calculateButton">Calculate</button>
  <pre id="result"></pre>

  <script>
    // 创建一个新的 Web Worker
    const worker = new Worker('worker.js');

    // 监听 Web Worker 发送的消息
    worker.onmessage = function(event) {
      if (event.data.error) {
        document.getElementById('result').textContent = `Error: ${event.data.error}`;
      } else {
        document.getElementById('result').textContent = `Result: ${event.data.result}`;
      }
    };

    // 监听按钮点击事件
    document.getElementById('calculateButton').addEventListener('click', function() {
      const operation = document.getElementById('operation').value;
      const a = parseFloat(document.getElementById('a').value);
      const b = parseFloat(document.getElementById('b').value);

      worker.postMessage({ operation, a, b });
    });
  </script>
</body>
</html>

11、self全局对象

self是web worker的全局对象,类似于主线程的window对象。以下是self对象中的一些常用方法和属性:

常用方法

1、消息传递

  • postMessage(data): 向创建该Worker的脚本发送数据

    self.postMessage('Hello form Worker')
    
  • onMessage(data): 接收从创建该Worker的脚本发送的消息的事件处理器

    self.onMessage = (event)=> {
        console.log('Receive message', event.data)
    }
    

2、定时器

  • setTimeout(func, dalay, ...args) 延迟执行一次
  • setInterval(func, dalay, ...args) 指定时间间隔重复执行函数
  • clearTimeout(timeoutId): 清除setTimeout设置的定时器
  • clearInterval(intervalId): 清除setInterval设置的定时器

3、网络请求

fetch(url, option): 发送网络请求

self.fetch('http://api.example.com/data')
    .then(response => response.json())
    .then(data=> {
        self.postMessage(data)
    })
    .catch(error => {
        self.postMessage({'error': error.message })
    })

4、导入脚本

importScripts(...urls):导入一个或者多个脚本

self.importScripts('script1', 'script2')

5、终止Worker

close(): 关闭当前Worker

self.close()

常用属性

1、navigator:提供浏览器的信息

console.log(self.navigator.userAgent)

2、location:提供关于Worker脚本URL的信息

console.log(self.location.href)

3、crypto:提供加密相关的功能

self.crypto.getRandomValues(new Uint32Array(1))

4、indexDB: 提供对indexDB数据库的访问

const request = self.indexDB.open('myDatabase', 1);
request.onsuccess = function(event) {
    const db = event.target.result;
    // 操作数据库
}

示例代码

// worker.js
self.onmessage = function(event) {
  if (event.data === 'start') {
    start();
  }
};

function start() {
  // 发送消息
  self.postMessage('Hello from worker!');

  // 定时器
  let count = 0;
  let intervalId = self.setInterval(() => {
    count++;
    self.postMessage(`Count: ${count}`);
  }, 1000);

  // 网络请求
  self.fetch('https://jsonplaceholder.typicode.com/posts')
    .then(response => response.json())
    .then(data => {
      self.postMessage(data);
    })
    .catch(error => {
      self.postMessage({ error: error.message });
    });

  // 导入脚本
  self.importScripts('helper.js');

  // 终止 Worker
  setTimeout(() => {
    self.close();
  }, 10000);
}
// 主线程代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Web Worker Example</title>
</head>
<body>
  <button id="startButton">Start Worker</button>
  <pre id="result"></pre>

  <script>
    // 创建一个新的 Web Worker
    const worker = new Worker('worker.js');

    // 监听 Web Worker 发送的消息
    worker.onmessage = function(event) {
      document.getElementById('result').textContent += event.data + '\n';
    };

    // 监听按钮点击事件
    document.getElementById('startButton').addEventListener('click', function() {
      worker.postMessage('start');
    });
  </script>
</body>
</html>