通过history.go(-1)或路由跳转离开了当前页面WebWorker依旧在执行怎么办

209 阅读2分钟

省流版本

当前页面所处的标签页关闭后,WebWorker会被强制关闭。
如果一直在一个标签页内,需要使用terminate()函数手动关闭WebWorker

页面功能

今天遇到了一个很神奇的BUG,在此记录一下。
一共有两个页面,一个“详情”,一个“采购单”,其中“采购单”需要从详情页面的“编辑采购单”按钮进入,是使用新标签页打开的方式进入的
当有用户进入采购单后,会立刻记录一个时间,并开始执行一个60秒一次的定时器,每60秒会调用API记录一次时间。
当详情里有另一个用户点击“编辑采购单”,如果当前时间和记录时间之差<1分钟,则无法进入(避免有两个人在同时编辑一个采购单)

定时器的代码是:

/// <reference lib="webworker" />

addEventListener('message', ({ data }) => {
  const timer = setInterval(() => {
    data += 1;
    postMessage(data);
  }, 1000);
});

采购单中执行定时器代码是:

const w = new Worker('./purchase-timer.worker', { type: 'module' });
    w.postMessage(0);
    w.onmessage = ({ data }) => {
      if (data % 60 === 0) {
        this.devManageService.postTickTime({
          pre_products_id: this.planId,
          op_date1: moment(new Date()).format('YYYY-MM-DD HH:mm:ss'),
          op_date1_user_id: this.general.getUserId()
        }).subscribe(res => { });
      }
    };

BUG描述

产品给我描述的BUG是:“他们有人退出了采购单,并且也保证没有页面处于采购单里,但其他人还是进不去,提示的弹窗里时间一直在增加”
咱们是无神论者,要相信科学相信程序,肯定不得有什么脏东西!
于是我亲自去页面实验了一下,发现并不会出现这样的BUG,在我纳闷的时候,产品成功复现了BUG情况,并叫我过去看。
看了之后我终于发现了问题所在:我返回详情的方式是直接关闭的标签页(因为采购单是新标签页嘛),而部分人的习惯是点击返回按钮回到详情页,这样就会导致虽然离开的采购单,但标签页依旧存在,定时器并不会关闭。
所以解决办法就很简单,当返回的时候手动关闭定时器即可。

解决办法

因为我的定时器只是在进入页面,ngOnInit周期的时候调用,是一个常量,无法在返回按钮中关闭,所以我设定了一个函数isOut去判断用户是否已经退出采购单页面。
在定时器的调用函数中,每次调用时根据isOut判断是继续计时,还是直接关闭计时器就可以了
修改后的代码为:

const w = new Worker('./purchase-timer.worker', { type: 'module' });
    w.postMessage(0);
    w.onmessage = ({ data }) => {
      if (data % 60 === 0 && !this.isOut) {
        this.devManageService.postTickTime({
          pre_products_id: this.planId,
          op_date1: moment(new Date()).format('YYYY-MM-DD HH:mm:ss'),
          op_date1_user_id: this.general.getUserId()
        }).subscribe(res => { });
      } else {
        w.terminate();
      }
    };