每日小记-Js中使用WebWorker遇到的问题

161 阅读2分钟

公司项目中遇到了要求使用webWorker进行数据下载的操作

让把之前在主线程发送axios请求的操作下放到webWorker

项目是在Capacitor框架中的,原先封装的request的请求方法调用了

Capacitor的初始化App方法,这个初始化方法操作了dom,所以不能在子线程中调用

原来的思路是在线程中实例化一个Axios的实例来进行请求的操作,因为请求涉及到了添加数据和请求头的操作

而这些数据都保持在主线程的框架插件PreferencesPlugin中,子线程拿不到只能通过postMessage

但是经过组长的沟通后,每次发送都直接使用axios.post() 而不是使用Axios的构造器

理由是只是简单的post请求,没必要使用构造器。但是还是需要去处理报错事件的,比如404,500等

原来的想法是在index.ts调用utils.ts工具类函数,utils调用webWorker脚本文件。

utils中监听onerroer事件捕获报错

webWorker中使用throw抛出错误

原来是这么写的

webWorker.ts

self.onmessage = function(e:MessageEvent<{
  config:{
    url:string,
    data:UpdateTableTask[],
    config:AxiosRequestConfig
  }
}>) {
  request(e.data.config)
}

/**
 * 发起请求
 *
 * @param config 请求参数
 */
async function request(requestParams: {
  url:string,
  data:UpdateTableTask[],
  config:AxiosRequestConfig
}) {
  try {
    const respone = await axios.post<ResponseEntity<EncryptedResponse>>(requestParams.url, requestParams.data, requestParams.config)
    self.postMessage({
      type: 'success',
      data: respone.data.data
    })
  } catch (error) {
    throw new Error(error)
  }
}

utils.ts

export function webWorkerRequest(config:{
  url:string,
  data:UpdateTableTask[],
  config:AxiosRequestConfig
}): Promise<ResponseEntity<EncryptedResponse>> {
  if (Worker) {
    worker = new Request()
    return new Promise((resolve, reject) => {
      worker.onmessage = (event) => {
        if (event.data.type === 'error') {
          reject(event.data.message)
        } else {
          resolve(event.data)
        }
        worker.terminate()
      }
      worker.postMessage({
        config
      })
      Worker.onerrron = (error) => {
        reject(error)
      }
    })
  } else {
    throw new Error('Web Worker不可用')
  }
}

在子线程的catch中可以正常的捕获到异常打印

但是就是没办法在utils中的onerror事件中捕获

后来经过几次测试,发现在异步函数中的报错不会被主线程的onerror监听事件捕获

不管是使用async await 还是Promise只要是异步的主线程都接收不到

随后改成使用postMessage的模式,通过一个type区分成功还是失败去传递

webWorker.ts

async function request(requestParams: {
  url:string,
  data:UpdateTableTask[],
  config:AxiosRequestConfig
}) {
  try {
    const respone = await axios.post<ResponseEntity<EncryptedResponse>>(requestParams.url, requestParams.data, requestParams.config)
    self.postMessage({
      type: 'success',
      data: respone.data.data
    })
  } catch (error) {
    console.error(error)
    self.postMessage({
      type: 'error',
      message: (error as AxiosError).message ?? '请求失败'
    })
  }
}

这样主线程就可以正常的接收到子线程的报错消息。