共计 2857 个字符,预计需要花费 8 分钟才能阅读完成。
这个不是很常用的功能,但是想收集客户端的错误信息时却很有必要了解下。捕获分为两个方面:
收集 JS 语法、执行错误
最初的是想直接获取控制台的错误信息;然而这并不大可行,JS 并没有这样的功能。
转换下思路
在错误发生时,将错误进行存储。
原生 JS 实现方式:
通过重载 window 对象下的 onerror 函数,可以截取到这些信息。
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 文件。
angular 环境下无法使用 window.ondrror. 原因是 angular 体制内的代码通过 $even 解析后并不会将错误移交给 window.onerror 函数
但是 angular 在解析时会将所有的语法、执行错误时将会触发 $ExceptionHandlerProvider
函数:
function $ExceptionHandlerProvider() {this.$get = ['$log', function($log) {return function(exception, cause) {$log.error.apply($log, arguments);
};
}];
}
$ExceptionHandlerProvider
函数将会调用 consoleLog('error')
函数
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.apply $window.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 对象