文章
问答
冒泡
在React中使用Web Worker

前言

为了确保UI的响应性和避免复杂的同步问题,JavaScript被设计为单线程。然而在Web Worker标准中提供了浏览器运行多线程的能力。不过Web Worker运行在全局作用域之外,它们无法访问Window对象和Document对象,和主线程之间通信也只能通过异步消息传递机制实现。

由于原生的Web Worker写法比较复杂,这里我们使用useWorker,一个以React Hooks的方式简单使用Web Worker API的库。

安装

npm install --save @koale/useworker

引用

import { useWorker, WORKER_STATUS } from "@koale/useworker";

这是一个很小的库,它只提供了useWokrer这个hooks和worker状态的枚举类。

例子

由于使用比较简单,不多废话直接看代码。(ps: 我是通过create-react-app创建的项目)

import React, {useEffect, useState} from 'react';
import logo from './logo.svg';
import './App.css';
import {useWorker, WORKER_STATUS} from "@koale/useworker";
import toast, {Toaster} from 'react-hot-toast';


let turn = 0;
const infiniteLoop = () => {
  const logo = document.querySelector(".App-logo") as HTMLElement;
  turn += 8;
  logo.style.transform = `rotate(${turn % 360}deg)`;
}

const bubbleSort = (input: number[]) => {
  let swap;
  let n = input.length - 1;
  const sortedArray = input.slice();
  do {
    swap = false;
    for (let index = 0; index < n; index += 1) {
      if (sortedArray[index] > sortedArray[index + 1]) {
        const tmp = sortedArray[index];
        sortedArray[index] = sortedArray[index + 1];
        sortedArray[index + 1] = tmp;
        swap = true;
      }
    }
    n -= 1;
  } while (swap);

  return sortedArray;
};


const numbers = [...Array(50000)].map(() =>
  Math.floor(Math.random() * 1000000)
                                     );

function App() {
  const [sortStatus, setSortStatus] = useState(false);
  const [sortWorker, {status: sortWorkerStatus}] = useWorker(bubbleSort);

  useEffect(() => {
    const loopInterval = setInterval(infiniteLoop, 100);
    return () => clearInterval(loopInterval);
  }, []);

  const onSortClick = () => {
    setSortStatus(true);
    const result = bubbleSort(numbers);
    setSortStatus(false);
    toast("Finished: Sort");
    console.log("Bubble Sort", result);
  };

  const onWorkerSortClick = () => {
    sortWorker(numbers).then(result => {
      toast("Finished: Sort using useWorker.");
      console.log("Bubble Sort useWorker()", result);
    });
  };


  return (
    <div className="App">
      <Toaster/>
      <header className="App-header">
        <h1 className="App-title">useWorker demo</h1>
        <img src={logo} className="App-logo" alt="logo"/>
        <div>
          <section className="App-section">
            <button
              type="button"
              disabled={sortStatus}
              className="App-button"
              onClick={() => onSortClick()}
              >
              {sortStatus ? `Loading...` : `Bubble Sort`}
            </button>
            <button
              type="button"
              disabled={sortWorkerStatus === WORKER_STATUS.RUNNING}
              className="App-button"
              onClick={() => onWorkerSortClick()}
              >
              {sortWorkerStatus === WORKER_STATUS.RUNNING
                ? `Loading...`
              : `Bubble Sort useWorker()`}
            </button>
          </section>
        </div>
            </header>
        </div>
    );
}

export default App;

效果图如下

这里可以看到,我们先让图标一直转动表示ui主线程一直在执行,当我们不使用Web Worker执行计算任务时很明显会阻塞主线程,而当我们使用Web Worker时并不会影响主线程的执行。


关于作者

TimothyC
天不造人上之人,亦不造人下之人
获得点赞
文章被阅读