«

web worker实现倒计时

emer 发布于 2023-1-29 18:54   824 次阅读     


<CountDownTimer endTime={1569834068266} onEnd={this.onEndHandler.bind(this)} />


CountDownTimer.jsx

import React from "react";
import styled from "styled-components";
import WebWorker from "../../utils/worker";

let work = function() {
  let timer = null;
  this.onmessage = e => {
    const { endTime, state } = e.data;
    if (state === "stop") {
      if (timer) {
        clearInterval(timer);
        timer = null;
      }
      return;
    } else if (state === "start") {
      let interval = 1000;
      if (!timer) {
        timer = setInterval(() => {
          this.postMessage(endTime - new Date().getTime());
        }, interval);
      }
    }
  };
};

let worker = new WebWorker(work);

/**
 * 计算相对时间字符串
 * @param {number} time 13位时间戳
 */
function relativeTime(time) {
  if (time <= 0) {
    return "00:00";
  }
  const minute = Number.parseInt(time / 1000 / 60, 10);
  const second = Number.parseInt((time / 1000) % 60, 10);
  return `${minute > 9 ? minute : "0" + minute}:${
    second > 9 ? second : "0" + second
  }`;
}

export default function CountDownTimer({
  endTime,
  onEnd = Function.prototype
}) {
  const initTime = relativeTime(endTime - new Date().getTime());
  let [time, setTime] = React.useState(initTime);

  worker.onmessage = e => {
    if (e.data <= 0) {
      worker.postMessage({ state: "stop" });
      return;
    }
    setTime(relativeTime(e.data));
  };

  React.useEffect(() => {
    worker.postMessage({
      state: "start",
      endTime: Number.parseInt(endTime, 10)
    });
    return function() {
      worker.postMessage({ state: "stop" });
    };
  }, [endTime]);

  React.useEffect(() => {
    if (time === "00:00") {
      return function() {
        onEnd();
        worker.postMessage({ state: "stop" });
      };
    }
  }, [time, endTime, onEnd]);

  const Time = styled.span`
    font-size: 1.6rem;
    font-weight: 700;
    vertical-align: middle;
  `;
  return (
    <div>
      倒计时:<Time>{time}</Time>
    </div>
  );
}

worker.js

export default class WebWorker {
  constructor(worker) {
    const code = worker.toString();
    const blob = new Blob([`(${code})()`]);
    return new Worker(URL.createObjectURL(blob));
  }
}