js捕获错误信息

这个不是很经常使用的功能, 可是想收集客户端的错误信息时却颇有必要了解下。 捕获分为两个方面:javascript

收集JS语法、执行错误

最初的是想直接获取控制台的错误信息; 然而这并不大可行,JS并无这样的功能。java

转换下思路git

在错误发生时,将错误进行存储。github

原生JS实现方式:

经过重载 window 对象下的 onerror 函数, 能够截取到这些信息。ajax

window.onerror = function(errorMessage, scriptURI, lineNumber,columnNumber,errorObj) {
   console.log("错误信息:" , errorMessage);
   console.log("出错文件:" , scriptURI);
   console.log("出错行号:" , lineNumber);
   console.log("出错列号:" , columnNumber);
   console.log("错误详情:" , errorObj);
}
复制代码

框架实现方式:

只在angular 下作了实现,没有实现过的框架没有发言权;接下来将以angular为例。但要注意的是在部分框下这种方式是不生效的,缘由是在框架解析代码前,全部的代码能够理解为都是文本而非js文件。bash

angular 环境下没法使用window.ondrror. 缘由是angular体制内的代码经过$even 解析后并不会将错误移交给 window.onerror 函数app

可是 angular 在解析时会将全部的语法、执行错误时将会触发 $ExceptionHandlerProvider 函数:框架

function $ExceptionHandlerProvider() {
  this.$get = ['$log', function($log) {
    return function(exception, cause) {
      $log.error.apply($log, arguments);
    };
  }];
}
复制代码

$ExceptionHandlerProvider 函数将会调用 consoleLog('error') 函数ide

this.$get = ['$window', function($window) {
return {
  /**
   * @ngdoc method
   * @name $log#log
   *
   * @description
   * Write a log message
   */
  log: consoleLog('log'),
  /**
   * @ngdoc method
   * @name $log#info
   *
   * @description
   * Write an information message
   */
  info: consoleLog('info'),
  /**
   * @ngdoc method
   * @name $log#warn
   *
   * @description
   * Write a warning message
   */
  warn: consoleLog('warn'),
  /**
   * @ngdoc method
   * @name $log#error
   *
   * @description
   * Write an error message
   */
  error: consoleLog('error'),
  /**
   * @ngdoc method
   * @name $log#debug
   *
   * @description
   * Write a debug message
   */
  debug: (function() {
    var fn = consoleLog('debug');
    return function() {
      if (debug) {
        fn.apply(self, arguments);
      }
    };
  }())
};
function consoleLog(type) {
  var console = $window.console || {},
      logFn = console[type] || console.log || noop,
      hasApply = false;
  // Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
  // The reason behind this is that console.log has type "object" in IE8...
  try {
    hasApply = !!logFn.apply;
  } catch (e) {}
  if (hasApply) {
    return function() {
      var args = [];
      forEach(arguments, function(arg) {
        args.push(formatError(arg));
      });
      return logFn.apply(console, args);
    };
  }
  // we are IE which either doesn't have window.console => this is noop and we do nothing, // or we are IE where console.log doesn't have apply so we log at least first 2 args
  return function(arg1, arg2) {
    logFn(arg1, arg2 == null ? '' : arg2);
  };
}
复制代码

最终这些错误会流入原生console.error内, 因此在angular下捕获这些错误将变的异常简单。仅仅须要重置console.error方法,以下所示:函数

resetConsole() {
    window.console._error = window.console.error;
    window.console.error = info => {
        // 在这里执行错误存储或发送
        window.console._error(info);
    };
}
复制代码

angular 在解析错误时, 会经过log.error.applywindow.console.error方法. 因此在这里将 console.error 进行重置后, 语法、执行错误也会一并收集到。

收集请求错误

各框架都会将 XMLHttpRequest 进行封装, 能够找到对应的errror函数内将错误进行捕获。

原生实现收集请求错前, 须要先对XMLHttpRequest进行封装,示例以下:

var ajax = function(type, url, callback){
    var xhr = new XMLHttpRequest();
    xhr.open(type, url);
    xhr.onreadystatechange = function() {
        if (xhr.readyState !== 4) {
            return;
        }
        if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
            callback();
        } else {
            console.log('收集到一条错误');// 在这里收集错误信息
        }
    };
    xhr.send(null);
}
// 由于.ccccccom这个路径是不存在的, 因此会执行收集区域的代码。
ajax('GET', 'http://www.lovejavascript.ccccccom', function(a){console.log(a)});
复制代码

若是对 XMLHttpRequest 封装感兴趣, 能够看下我写的 jTool类库中的 ajax 对象