JavaScript代码不能被阻断的稳定性建设

2022-10-11 18:10:09
目录
背景最常见的js被阻断的情况解决办法容易被我们忽视的点1. 没考虑到错误上报2. 错用throw3. 异步代码catch不到,还是会被阻断4. import()和require()的错误捕获表现不一致

背景

稳定性建设之JavaScript代码不能被阻断

js代码可能会因为某些原因,导致出错,进而整个后续代码有可能都被阻断。直接影响线上的稳定性

最常见的js被阻断的情况

console.log(111)
// 预期 a = {}
// 结果
a = undefined
a.a = 1
console.log(222) // js代码不能执行到这一行

这个代码很明显会报错,在a.a = 1这一行开始报错,后续的js代码被阻断了,console.log(222)打印不出来

解决办法

    解决办法也很简单,用>
    console.log(111)
    try {
      // 预期 a = {}
      // 结果
      a = undefined
      a.a = 1
    } catch (e) {
      console.error(e)
    }
    console.log(222) // js代码可以执行到这一行
    

    容易被我们忽视的点

    1.>
      上面的demo没有考虑错误上报,发生错误时,外部根本捕获不到(即使你接入了sentry类的产品),因为error被try catch给吃掉了
      try {
        // 预期 a = {} 
        // 结果 
        a = undefined 
        a.a = 1
      } catch (e) {
        console.error(e)
        // 公司内部的上报函数
        someReportFunction('sendEvent', {
          name: 'try_catch_error',
          params: {
            errorMsg: e.message,
            errorStack: e.stack
          },
        });
      }
      

      2.>

      随便点开一篇文章,就有人在误人子弟,教别人用 throw, throw这个东西是不能乱用的,因为他会阻断代码,重要的事情说三遍,throw会阻断代码,throw会阻断代码,throw会阻断代码

      例如:

      console.log(111)
      try {
        // 预期 a = {}
        // 结果
        a = undefined
        a.a = 1
      } catch (e) {
        console.error(e)
        throw e // throw会阻断代码,导致下面不执行
      }
      console.log(222) // 不能执行到这一行
      

      当然throw也不是一无是处,但是,他只能在try{ 里面使用 },不能在try之外的地方使用throw,包括catch

      console.log(111)
      try {
        throw new Error(111)
      } catch (e) {
        console.error(e)
      }
      console.log(222)
      
      function getData () {
          if (...) {
              ...
          } else {
              throw new Error(111)
          }
      }
      console.log(111)
      try {
        getData()
      } catch (e) {
        console.error(e)
      }
      console.log(222)
      

      3.>
      console.log(111111111)
      try {
        setTimeout(() => {
          a = undefined
          a.a = 1 // 代码被阻断于此
          console.log('error') // 不能执行到这一行
        }, 0)
      } catch (e) {
        console.error(e) // 异步代码catch不到
      }
      console.log(222222222)
      setTimeout(() => {
        console.log('setTimeout') // 浏览器可以执行到这一行,node的不行(node14和16版本都test了)
      }, 2000)
      

      4.>
      // a.js
      console.log(111111111)
      try {
        require('./b.js')
      } catch (e) {
        console.log('error') // 错误会被正常catch到
        console.error(e)
      }
      console.log(222222222)
      setTimeout(() => {
        console.log('setTimeout')
      }, 2000)
      // b.js
      console.log(1)
      a = undefined
      a.a = 1
      console.log(2)
      // 结果打印 (require被正常捕获)
      111111111
      1
      error
      TypeError: Cannot set property 'a' of undefined
          ...
          ...
      222222222
      setTimeout
      
        同样的代码换成,import()
        // a.js
        console.log(111111111)
        try {
          import('./b.js')
        } catch (e) {
          console.log('error') // 错误没有被catch到
          console.error(e) 
        }
        console.log(222222222)
        setTimeout(() => {
          console.log('setTimeout')
        }, 2000)
        // b.js
        console.log(1)
        a = undefined
        a.a = 1
        console.log(2)
        // 结果打印 (import的 错误没有被catch到)
        111111111
        222222222
        1
        (node:92673) UnhandledPromiseRejectionWarning: TypeError: Cannot set property 'a' of undefined
            ...
        setTimeout
        

        正确捕获import()的方式:其实import()是一个promise,用promise的方法去catch就好了

        import('./b.js') 
          .catch(e => { 
            console.log('error') 
            console.error(e) 
          })
        

        结论:

          try catch 不能捕获import()模块的错误,require可以被捕获import() 用promise的方法去catch就好了

          背景:

            require是运行时加载(可以理解为,函数调用)import()是动态import,会延迟加载,是异步任务(微任务),是promise

            以上就是JavaScript代码不能被阻断的稳定性建设的详细内容,更多关于JavaScript稳定建设的资料请关注易采站长站其它相关文章!