【稳定性】监控页面崩溃

1,163 阅读2分钟

我正在参加「掘金·启航计划」

页面崩溃 → 主线程卡死 → 应该单独开一个线程

Worker

浏览器兼容性检测

if (window.Worker){
  ...
}

Web Worker

web worker 的上下文中没有 window,也就是没有 document 等一系列 DOM 的方法

专用 worker

var myWorker = new Worker('worker.js')

myWorker.postMessage("hello")
myWorker.onmessage = (msg) => {}

// 终止 worker
myWorker.terinate()

worker 脚本中存在错误

当 worker 出现运行中错误时,它的 onerror 事件处理函数会被调用。它会收到一个扩展了 ErrorEvent接口的名为 error的事件。

注意:在我们的woker脚本中涉及网络上报,那么需要分成两种情况

  1. 如果业务希望由于监控本身的错误也被上报的话,那么我们可以在 onError 中自定义上报事件( 那么自定义上报事件的错误呢?隔着套娃? )

  2. 如果业务不希望的话,则需要关注内部调用 fetch / xhr.send 其实是被改写的,是否需要做一些特殊的处理

共享worker

一个共享 worker 可以被多个脚本使用——即使这些脚本正在被不同的 window、iframe 或者 worker 访问

只需要保证用到共享 worker 的页面是同源的就OK了

具体的内容可以去MDN上再详细了解一下,因为作为监控,使用 专用 worker 可能更加合适

需求分析

崩溃的来源

  1. 运行时的一些死循环

  2. 内存泄漏 → 爆栈了

  3. 特别长的任务

目标

  1. 需要判断是不是因为内存的问题导致的 → 上报的数据携带内存信息

  2. long task 误判减少 → 时间阈值可以再变大一些,比如 10s

具体设计

  1. 服务端心跳检测,通过WebSocket/或者短轮询的方式,向服务端发送请求;一旦页面崩溃,就不会再发送了,服务端判断页面挂了,然后数据入库;

弊端也很明显,资源占用严重,不论是服务端资源,还是客户端资源

  1. 使用 Web Worker 单独开辟一个线程,进行心跳检测
  • Web Worker

    1. 定期 ( 6s ) 检查发送给客户端,客户端及时响应。
    2. 定期 ( 3s ) 检查当前客户端反应的状况
    3. 检测到崩溃后 → 行异常上报。
  • 客戶端 接受到 Web Worker 的刺激后,返回一个心跳包

代码实现

主线程

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import './index.css'
const worker = new Worker("http://127.0.0.1:5173/src/work.js")
console.log(worker)
worker.onmessage =(e)=>{
  console.log(e, "心跳检测啦")
  worker.postMessage("正在活跃")
}
ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
)

Worker.js

let status = "alive"
function post(){
    console.log("卡死啦")
}
setInterval(()=>{
    self.postMessage("hartBeat");
    status = "dead";
    setTimeout(()=>{
        if(status == "dead"){
            post();
        }
    }, 3000)
}, 6000)

self.onmessage = ()=>{
    status = "alive"
    console.log("接收到主线程啦")
}