前端错误类型与处理方式

1,391 阅读3分钟

错误类型:

常见JS执行错误:

  1. SyntaxError:语法错误,解析时发生语法错误
    // 在控制台运行
    
    // 一般语法错误
    const xx,
    
    // 特殊语法错误
    JSON.parse('');
    
    • SyntaxError在构建阶段,甚至本地开发阶段就会被发现;
    • 而特殊语法错误可以被所有错误捕获方式捕获。
  2. TypeError:类型错误,值不是所期待的类型
    // 控制台运行 
    const person = undefined;
    person.name;
    
  3. ReferenceError:引用错误,引用未声明的变量
    // 控制台运行 
    nodefined;
    
  4. RangeError:范围错误,当一个值不在其所允许的范围或者集合中
    // 控制台运行
    // 爆栈
    (function fn() {
        fn();
    })();
    

网络错误:

  1. ResourceError:资源加载错误
    // 控制台运行 
    new Image().src = '/remote/image/notdeinfed.png';
    
  2. HttpError:http请求错误
    // 控制台运行 
    fetch('/remote/notdefined');
    

错误捕获:

try/catch:

能捕获常规的运行时错误,但是语法错误异步错误不行。

  // 一般语法错误 ❌
  try {
    const xx,
  } catch (error) {
    console.log('一般语法错误: ', error);
  }
  
  // 特殊语法错误 ✅
  try {
    JSON.parse('');
  } catch (error) {
    console.log('特殊语法错误: ', error);
  }

  // 类型错误 ✅
  try {
    const person = undefined;
    person.name;
  } catch (error) {
    console.log('类型错误: ', error);
  }

  // 引用错误 ✅
  try {
    a;
  } catch (error) {
    console.log('引用错误: ', error);
  }

  // 范围错误 ✅
  try {
    (function fn() {
      fn();
    })();
  } catch (error) {
    console.log('范围错误: ', error);
  }
  
  // 下面都属于异步错误:

  // 资源加载错误 ❌
  try {
    new Image().src = 'aaa';
  } catch (error) {
    console.log('资源加载错误: ', error);
  }

  // http请求错误 ❌
  try {
    fetch('aaa');
  } catch (error) {
    console.log('http请求错误: ', error);
  }

  // promise异步错误 ❌
  try {
    new Promise(() => {
      a;
    });
  } catch (error) {
    console.log('promise异步错误: ', error);
  }

  // setTimeout/setInterval异步错误 ❌
  try {
    setTimeout(() => {
      b;
    }, 0);
  } catch (error) {
    console.log('setTimeout/setInterval异步错误: ', error);
  }

window.onerror

当 JS 运行时错误发生时,window 会触发一个 ErrorEvent 接口的 error 事件。

/**
* @param {String}  message    错误信息
* @param {String}  source    出错文件
* @param {Number}  lineno    行号
* @param {Number}  colno    列号
* @param {Object}  error  Error对象
*/

window.onerror = function(message, source, lineno, colno, error) {
   console.log('捕获到异常:', {message, source, lineno, colno, error});
};
window.onerror = function(message, source, lineno, colno, error) {
   console.log('捕获到异常:', {message, source, lineno, colno, error});
};
window.onload = function () {
  // 一般语法错误 ❌
  const xx,
  
  // 特殊语法错误 ✅
  JSON.parse('');

  // 类型错误 ✅
  const person = undefined;
  person.name;

  // 引用错误 ✅
  a;

  // 范围错误 ✅
  (function fn() {
    fn();
  })();

  // 资源加载错误 ❌
  new Image().src = 'aaa';

  // http请求错误 ❌
  fetch('aaa');

  // promise异步错误 ❌
  new Promise(() => {
    a;
  });

  // setTimeout/setInterval异步错误 ✅
  setTimeout(() => {
    b;
  }, 0);
};

window.onerror不能捕获语法错误和promise异步错误(包括网络错误)。

window.addEventListener('error', fn, true);

当一项资源(如图片或脚本)加载失败,加载资源的元素会触发一个 Event 接口的 error 事件,这些 error 事件不会向上冒泡到 window,但能被捕获。而window.onerror不能监测捕获。

window.addEventListener('error', fn)对于js的错误检测和window.onerror相同。

但是window.addEventListener('error', fn, true)可以检测出html标签资源加载错误。

  window.addEventListener('error', (err) => {
    console.log('捕获到异常:', err);
  }, true);

  const img = document.createElement('img');
  img.src = 'aaa';
  // 不加这行代码,会进行资源请求,但是错误不会被捕获
  document.body.appendChild(img);

  const script = document.createElement('script');
  script.src = 'bbb';
  document.body.appendChild(script);

  const link = document.createElement('link');
  link.href = 'ccc';
  link.rel = 'stylesheet';
  document.body.appendChild(link);

到目前为止,还有语法错误promise异步错误new Image资源加载错误还没有捕获方法。

  • 语法错误可以在开发阶段依靠编辑器发现,上线的项目是不会出现语法错误的;
  • new Image资源加载错误使用的较少,可以通过img.onerror = fn来单独处理;
  • promise异步错误是需要着重考虑的!

Promise异步错误:

通过unhandledrejection事件捕获;

window.addEventListener('unhandledrejection', function (ev) {
  console.log('promise异步错误:', ev);
});
new Promise(() => {
  a;
});
fetch('aaa');

参考资料:

一篇讲透自研的前端错误监控