Introduction
捕获、报告、以及修正缺点是掩护和保持运用程序康健稳定运行的主要方面。由于Javascript代码紧张是在客户端运行、客户端环境又包括了各种各样的浏览器。因此使得肃清运用程序中 JS 缺点变得相对困难。关于如何报告在不同浏览器中引起的 JS 缺点依然也没有一个正式的规范。除此之外,浏览器在报告JS缺点也有些bug,这些缘故原由导致了肃清运用程序中的JS 缺点变得更加困难。这篇文章将会以以上问题作为出发点,剖析JS缺点的产生、JS缺点包含哪些部分、怎么去捕获一个JS缺点。期待这篇文章能够帮助到往后的开拓者更好的处理JS缺点、不同浏览器厂商能够就JS缺点找到一个标准的办理方案。
JavaScript 缺点阐发
一个JavaScript 缺点由 缺点信息(error message) 和 追溯栈(stack trace) 两个紧张部分组成。缺点信息是一个字符串用来描述代码出了什么问题。追溯栈用来记录JS缺点详细涌如今代码中的位置。JS 缺点可以通过两种办法产生、要么是浏览器自身在解析JavaScript代码时抛出错误,要么可以通过运用程序代码本身抛出错误。(译者注:例如可以通过throw new Error() 抛出错误)
产生一个JavaScript 缺点
当JavaScript代码不能够被浏览器精确实行的时候,浏览器就会抛出一个JS缺点,或者运用程序代码本身也可以直接抛出一个JS缺点。
例如:
var a = 3;a();
在如上例子中,a 变量类型是一个数值,不能够作为一个函数来调用实行。浏览器在解析上面代码时就会抛出如下缺点TypeError: a is not a function 并通过追溯栈指出代码出错的位置。
开拓者也常日在条件语句中当条件不知足的条件下,抛出一个缺点,例如:
if (!checkPrecondition()) { throw new Error(\公众Doesn't meet precondition!\"大众);}
在这种情形下,浏览器掌握台中的缺点信息如是Error: Dosen’t meet precondition!. 这条缺点也会包含一个追溯栈用来指示代码缺点的位置,通过浏览器抛出的缺点或是通过运用本身抛出的缺点可以通过相同的处理手段来处理。
开拓者可以通过不同办法来抛出一个JavaScript 缺点:
throw new Error(‘Problem description.’)throw Error(‘Problem description.’) <— equivalent to the first onethrow ‘Problem description.’ <— badthrow null <— even worse直接通过throw 操作符抛出一个字符串缺点(译者注:上面第三种办法)或者或者抛出null 这两种办法都是不推举的,由于浏览器无法就以上两种办法天生追溯栈,也就导致了无法追溯缺点在代码中的位置,由于推举抛出一个Error 工具,Error工具不仅包含一个缺点信息,同时也包含一个追溯栈这样你就可以很随意马虎通过追溯栈找到代码出错的行数了。
Error Messages
不同浏览器在就缺点信息的格式有不同的实现形式,比如上面的例子,在把一个原始类型的变量当做函数实行的时候,不同浏览器都在试图找到一个相同的办法来抛出这个缺点,但是又没有统一标准,因此相同的形式也就没有了担保,比如在Chrome和Firefox中,会利用{0} is not a function 形式来抛出错误信息,而IE11 会抛出Function expected 缺点信息(IE浏览器乃至不会指出是哪个变量被当做了函数调用而产生缺点)
然而,不同浏览器在就缺点信息上也有可能产生不合,比如当switch 语句中有多个default 语句时,Chrome会抛出 “More than one default clause in switch statement” 而FireFox会抛出”more than one switch default”. 当新特性加入到JavaScript措辞中时,缺点信息也该当实时更新。当处理随意马虎产生稠浊代码导致的缺点时,每每也须要利用到不同的处理手段。
你可以通过如下地址找到不同浏览器厂商在处理缺点信息上面的做法:
Firefox - http://mxr.mozilla.org/mozilla1.9.1/source/js/src/js.msgChrome - https://code.google.com/p/v8/source/browse/branches/bleeding_edge/src/messages.jsInternet Explorer - https://github.com/Microsoft/ChakraCore/blob/4e4d4f00f11b2ded23d1885e85fc26fcc96555da/lib/Parser/rterrors.hBrowsers will produce different error messages for some exceptions.
追溯栈格式
追溯栈是用来描述缺点涌如今代码中什么位置。追溯栈通过一系列相互关联的帧组成,每一帧描述一行特定的代码,追溯栈最上面的那一帧便是缺点抛出的位置,追溯栈下面的帧便是一个函数调用栈 - 也便是浏览器在实行JavaScript代码时一步一步怎么到抛出错误代码那一行的。
一个基本的追溯栈如下:
at throwError (http://mknichel.github.io/javascript-errors/throw-error-basic.html:8:9) at http://mknichel.github.io/javascript-errors/throw-error-basic.html:12:3
追溯栈中的每一帧由以下三个部分组成:一个函数名(发生缺点的代码不是在全局浸染域中实行),发生缺点的脚本在网络中的地址,以及发生缺点代码的行数和列数。
遗憾的是,追溯栈还没有一个标准形式,因此不同浏览器厂商在实现上也是有差异的。
IE 11的追溯栈和Chrome 的追溯栈很相似,除了在全局浸染域中的代码上有些差异:
at throwError (http://mknichel.github.io/javascript-errors/throw-error-basic.html:8:3) at Global code (http://mknichel.github.io/javascript-errors/throw-error-basic.html:12:3)
Firefox 的追溯栈如下格式:
throwError@http://mknichel.github.io/javascript-errors/throw-error-basic.html:8:9 @http://mknichel.github.io/javascript-errors/throw-error-basic.html:12:3
Safari 的追溯栈格式和Firefox很相似,但是仍旧有些出入:
throwError@http://mknichel.github.io/javascript-errors/throw-error-basic.html:8:18 global code@http://mknichel.github.io/javascript-errors/throw-error-basic.html:12:13
所有的浏览器厂商追溯栈基本信息差不多,但是格式上有些差异:
在上面Safari追溯栈的例子中,除了在追溯栈格式上和Chrome有差异外,发生缺点的列数也和Chrome和Firefox不同。在不同的缺点情境中,行数也会有所不同,比如如下代码:
(function namedFunction() { throwError(); })();
Chrome 会从throwError()开始计数行数,而IE11会从上面代码开始位置打算行数。这些不同浏览器之间在追溯栈格式上和计数上的差异也为后期解析追溯栈带来了困难。
通过如下网站 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/Stack 理解更多关于追溯栈的问题。
不同浏览器厂商在追溯栈格式以及列数上都有可能存在差异
深入研究,浏览器厂商关于追溯栈还有很多细微差异,将不才面部分详细谈论。
为匿名函数取名
默认情形下,匿名函数没有名字,同时在追溯栈中要么表现为空字符串要么便是Anonymous function(根据不同浏览器会有差异)。为了提升代码的可调试性,你该当为所用的函数添加一个函数名,以使得其在追溯栈中涌现,而不是空字符串或者Anonymous function。最大略的方法便是在所有的匿名函数前面加一个函数名,乃至该函数名不会在其他任何场合利用到。如下:
setTimeout(function nameOfTheAnonymousFunction() { ... }, 0);
上面代码的改变将使得追溯栈中也发生如下改变,从
at http://mknichel.github.io/javascript-errors/javascript-errors.js:125:17
变成了如下形式
at nameOfTheAnonymousFunction (http://mknichel.github.io/javascript-errors/javascript-errors.js:121:31)
上面给匿名函数添加姓名的方法可以担保函数名涌如今追溯栈中,这样也使得代码更易调试,通过如下网站你可以理解更多关于代码调试的信息。http://www.html5rocks.com/en/tutorials/developertools/async-call-stack/
将函数赋值给一个变量
浏览器常日也会利用匿名函数赋值给的变量作为函数名,在追溯帧中涌现。举个例子:
var fnVariableName = function() { ... };
浏览器会利用fnVariableName作为函数名在追溯栈中涌现。
at throwError (http://mknichel.github.io/javascript-errors/javascript-errors.js:27:9)
at fnVariableName (http://mknichel.github.io/javascript-errors/javascript-errors.js:169:37)
浏览器厂商在追溯栈上乃至还有更加细微的差异,如果一个函数被赋值给了一个变量,并且这个函数定义在其余一个函数内,险些所有的浏览器都会利用被赋值的变量作为追溯帧中的函数名,但是,Firefox有所不同,在Firefox中,会利用表面的函数名加上内部的函数名(变量名)作为追溯帧中的函数名。举个例子:
function throwErrorFromInnerFunctionAssignedToVariable() {
var fnVariableName = function() { throw new Error(\"大众foo\"大众); };
fnVariableName();
}
在Firefox中追溯帧格式如下:
throwErrorFromInnerFunctionAssignedToVariable/fnVariableName@http://mknichel.github.io/javascript-errors/javascript-errors.js:169:37
在其他的浏览器,追溯帧格式如下:
at fnVariableName (http://mknichel.github.io/javascript-errors/javascript-errors.js:169:37)
在一个函数定义在其余一个函数内部的情景下(闭包)Firefox会利用不同于其他浏览器厂商的格式来处理函数名
displayName 属性
除了IE11,函数名的展现也可以通过给函数定义一个displayName 属性,displayName会涌如今浏览器的devtools debugger中。而Safari displayName还会涌如今追溯帧中。
var someFunction = function() {};
someFunction.displayName = \"大众 # A longer description of the function.\公众;
虽然关于displayName还没有官方的标准,但是该属性已经在紧张的浏览器中实现了。通过如下网站你可以理解更多关于displayName的信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/displayName 和 http://www.alertdebugging.com/2009/04/29/building-a-better-javascript-profiler-with-webkit/
IE11不支持displayName属性
Safari displayName property bug Safari 会利用displayName作为函数名在追溯帧中涌现
通过编程来获取追溯栈
当抛出一个缺点但又没有追溯栈的时候(通过下面的内容理解更多),我们可以通过一些编程的手段来捕获追溯栈。
在Chrome中,可以大略的调用Error.captureStackTrace API来获取到追溯栈,关于该API的利用可以通过如下链接理解:https://github.com/v8/v8/wiki/Stack%20Trace%20API
举个例子:
function ignoreThisFunctionInStackTrace() { var err = new Error(); Error.captureStackTrace(err, ignoreThisFunctionInStackTrace); return err.stack;}
在其它浏览器中,追溯栈也可以通过天生一个缺点,然后通过stack属性来获取追溯栈。
var err = new Error('');
return err.stack;
但是在IE10中,只有当缺点真正抛出后才能够获取到追溯栈。
try { throw new Error('');} catch (e) { return e.stack;}
如果上面的方法都起浸染时,我们可以通过arguments.callee.caller 工具来粗糙的获取一个没有行数和列数的追溯栈,但是这种方法在ES5严格模式下不起浸染,因此这种方法也不是一种推举的做法。
Async stack traces
异步追溯栈
在JavaScript代码中异步代码是非常常见的。比如setTimeout的利用,或者Promise工具的利用,这些异步调用入口每每会给追溯栈带来问题,由于异步代码会天生一个新的实行高下文,而追溯栈又会重新形成追溯帧。
Chrome DevTools 已经支持了异步追溯栈,换句话说,追溯栈在追溯一个缺点的时候也会显示引入异步调用的那一调用帧。在利用setTimeout的情形下,在Chrome中会捕获谁调用了产生缺点的setTimeout 函数。关于上面内容,可以从如下网站获取信息:http://www.html5rocks.com/en/tutorials/developertools/async-call-stack/
一个异步追溯栈会采取如下形式:
throwError @ throw-error.js:2 setTimeout (async) throwErrorAsync @ throw-error.js:10 (anonymous function) @ throw-error-basic.html:14
目前,异步追溯栈只有Chrome DevTools支持,而且只有在DevTools代开的情形下才会捕获,在代码中通过Error工具不会获取到异步追溯栈。
虽然可以仿照异步调用栈,但是这每每会代指运用性能的花费,由于这种方法也显得并不可取。
Only Chrome supports async stack traces 只有Chrome DevTools原生支持异步追溯栈
命名行内JS代码或者利用eval情形
在追溯利用eval或者HTML 中写JS的情形,追溯栈常日会利用HTML的URL 以及代码实行的行数和列数。
例如:
at throwError (http://mknichel.github.io/javascript-errors/throw-error-basic.html:8:9)
at http://mknichel.github.io/javascript-errors/throw-error-basic.html:12:3
出于一些性能或代码优化的缘故原由,HTML中每每会有行内脚本,而且这种情形下,URL, 行数、列数也有可能出错,为理解决这些问题,Chrome和Firefox 支持//# sourceURL= 声明,(Safari 和 IE 暂不支持)。通过这种形式声明的URL会在追溯栈中利用到,而且行数和列数也会通过<script> 标签开始打算。比如上面相同的缺点,通过sourceURL的声明,每每会在追溯帧后面添加一个inline.js.
at throwError (http://mknichel.github.io/javascript-errors/inline.js:8:9) at http://mknichel.github.io/javascript-errors/inline.js:12:3
担保行内脚本及利用eval的情形下追溯栈的精确性依然是迫不及待的技能问题。
可以通过如下网站理解更多关于sourceurl的内容http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/
Lack of sourceURL support Safari 和 IE 现在都不支持sourceURL 申明来命名 行内脚本和利用eval情形。如果你在这两个浏览器内利用行内脚本,那么在这些脚本中涌现的缺点每每不能够很好的解析
Chrome bug for computing line numbers with sourceURL 直到Chrome 42, Chrome也没有精确得打算行内脚本中发生缺点的行数。访问如下链接,理解更多关于行内脚本内容:https://bugs.chromium.org/p/v8/issues/detail?id=3920
Chrome bug in line numbers from inline scripts 在利用sourceURL声明情形下,在行内脚本中,行数常日是从html文档开始位置开始计数,而不是从script标签处开始计数的,从html文档开始计数常日被认为是禁绝确的 https://code.google.com/p/chromium/issues/detail?id=578269
利用eval情景下的追溯栈
除了是否利用sourceURL声明,在代码中利用eval的情形下,不同浏览器在追溯栈上也有诸多差异:举个例子:
在Chrome在代码中利用eval,追溯栈如下:
Error: Error from eval
at evaledFunction (eval at evalError (http://mknichel.github.io/javascript-errors/javascript-errors.js:137:3), <anonymous>:1:36)
at eval (eval at evalError (http://mknichel.github.io/javascript-errors/javascript-errors.js:137:3), <anonymous>:1:68)
at evalError (http://mknichel.github.io/javascript-errors/javascript-errors.js:137:3)
在IE11,中会是这样的。
Error from eval
at evaledFunction (eval code:1:30)
at eval code (eval code:1:2)
at evalError (http://mknichel.github.io/javascript-errors/javascript-errors.js:137:3)
在Safari中:
Error from eval evaledFunction eval code eval@[native code] evalError@http://mknichel.github.io/javascript-errors/javascript-errors.js:137:7
在Firefox中:
Error from eval
evaledFunction@http://mknichel.github.io/javascript-errors/javascript-errors.js line 137 > eval:1:36
@http://mknichel.github.io/javascript-errors/javascript-errors.js line 137 > eval:1:11
evalError@http://mknichel.github.io/javascript-errors/javascript-errors.js:137:3
兼容不同浏览器解析eval代码将变得非常困难。
Different eval stack trace format across browsers 不同浏览器都有自己处理eval代码缺点的追溯栈格式
捕获JavaScript 缺点
当创造运用程序中有缺点的时候,程序中一些代码必须能够捕获缺点,并且能够报告缺点。现目前已经有很多方法能够捕获缺点,他们有各自的优点和缺陷:
window.onerror
window.onerror是开始捕获缺点最大略的方法了,通过在window.onerror上定义一个事宜监听函数,程序中其他代码产生的未被捕获的缺点每每就会被window.onerror上面注册的监听函数捕获到。并且同时捕获到一些关于缺点的信息。举个例子:
window.onerror = function(msg, url, line, col, err) { console.log('Application encountered an error: ' + msg); console.log('Stack trace: ' + err.stack);}
访问https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onerror理解更过关于window.onerror的内容
在利用window.onerror方法捕获缺点存在如下问题:
No Error object provided
window.onerror注册的监听函数的第五个参数是一个Error工具,这是2013年加入到WHATWG规范中的。https://html.spec.whatwg.org/multipage/webappapis.html#errorevent.Chrome,Firefox, IE11现在都能够精确的在window.onerror中供应一个error工具(并且带有一个stack属性),但是Safari 和 IE10现在还没有,Firefox是从14版本加入Error工具的 (https://bugzilla.mozilla.org/show_bug.cgi?id=355430) ,而Chrome是从2013年晚期在window.onerror监听函数中加入Error工具的 (https://mikewest.org/2013/08/debugging-runtime-errors-with-window-onerror, https://code.google.com/p/chromium/issues/detail?id=147127)。
Lack of support for Error in window.onerror Safari 和 IE10还不支持在window.onerror的回调函数中利用第五个参数,也便是一个Error工具并带有一个追溯栈
Cross domain sanitization
在Chrome中,window.onerror能够检测到从别的域引用的script文件中的缺点(译者注:比如从CDN上面引用的jQuery源文件)并且将这些缺点标记为Script error .如果你不想处理这些从别的域引入的script文件,那么可以在程序中通过script error标记将其过滤掉。然而,在Firefox、Safari或者IE11中,并不会引入跨域的JS缺点,及时在Chrome中,如果利用try/catch将这些讨厌的代码包围,那么Chrome也不会再检测到这些跨域缺点。
在Chrome中,如果你想通过window.onerror来获取到完全的跨域缺点信息,那么这些跨域资源必须供应得当的跨域头信息。可以参考下面地址 https://mikewest.org/2013/08/debugging-runtime-errors-with-window-onerror
Cross domain sanitization in window.onerror Chrome 是唯一一个能够通过window.onerror检测到其他源上面的文件缺点的浏览器,要么将其过滤掉,要么为其设置得当的跨域头信息
Chrome Extensions
在早期版本的Chrome浏览器中,安装在用户电脑中Chrome插件抛出的JS缺点依然会被window.onerror检测到,这一bug在新版本的Chrome中已经被改动,拜会下面Chrome插件部分。
window.addEventListener(“error”)
window.addEventListener(“error”) API 的效果和window.onerror API相同,可以通过下面网站理解更多信息:http://www.w3.org/html/wg/drafts/html/master/webappapis.html#runtime-script-errors
Showing errors in DevTools console for development
通过window.error并不能够阻挡缺点显示在浏览器掌握台中,这常日是精确的,也是开拓须要的,由于开拓者可以很随意马虎从掌握台中看到缺点信息。如果你不肯望这些缺点在生产环境中显示给终极用户,那么在window.addEventListener中利用e.preventDefault() 可以有效的避免缺点显示在掌握台上。举个例子:(译者注:该例子为译者举例)
window.addEventListener('error', function(e) { e.preventDefault() //report error})
推举做法
window.onerror是捕获JS 缺点最好的方法,我们推举只有当JS缺点带有一个合法的Error 工具和追溯栈时才将其报告给做事器(译者注:搜集缺点的做事器),由于其他不合法的缺点不随意马虎被剖析,或者你可能会捕获到很多垃圾JS缺点(从Chrome插件中得到)或者是从跨域资源上获取到一些信息不全的缺点。
try/catch
鉴于以上window.onerror的不敷之处,我们不能够完备依赖于window.onerror来获取全部的JS缺点,如果只是须要在本地(译者注:并不肯望把缺点抛到全局,然后在掌握台中显示)捕获缺点,那么try/catch 代码块将是一个更好的选择,我们乃至可以将所用的JavaScript代码通过一个try/catch包围来获取window.onerror获取不到的缺点。这种方法能够改进有些浏览器不支持window.onerror的情形,但是try/catch依然会有如下一些劣势:
不能够捕获所有缺点
try/catch并不能够捕获程序中的所有缺点,比如try/catch就不能够捕获window.setTimeout异步操作抛出的缺点。但是Try/catch可以通过 Protected Entry Points 来改进这一缺陷。(译者注:虽然try/catch不能够捕获异步代码中的缺点,但是其将会把缺点抛向全局然后window.onerror可以将其捕获,Chrome中已测试)
Use protected entry points with try/catch try/catch 包围所有的程序代码,但是依然不能够捕获所有的JS缺点
try/catch 不利于性能优化
在V8(其他JS引擎也可能涌现相同情形)函数中利用了try/catch语句不能够被V8编译器优化。参考 http://www.html5rocks.com/en/tutorials/speed/v8/
Protected Entry Points
一个JavaScript的’’代码入口’’便是指任意开始实行你代码的浏览器API.例如,setTimeout、setInterval、事宜监听函数、XHR、web sockets、或者promise。都可以是代码入口。通过这些入口代码抛出的JS缺点能够被window.onerror捕获到,但是遗憾的是,在浏览器中这些代码入口抛出的缺点并不是完全的Error工具,(译者注:在最新版Chrome中可以捕获到完全的Error工具),由于try/catch也不能够捕获到代码入口产生的JS缺点,由于一个�可替代的方案急需被利用。
光彩的是,JavaScript运行我们对这些入口代码进行包装,这样便是的在函数调用之前我们就可以引入try/catch语句,这样也就能够捕获入口代码抛出的缺点了。
每个入口代码须要进行一些改变(译者注:猴子补丁),这也便是所谓的「保护」代码入口,举个例子如下:
Promises
遗憾的是,在Promises中产生的缺点很随意马虎就被粉饰而不能够不雅观察到,Promise中的缺点只会被rejection处理函数(译者注:便是.catch())捕获到,而不会在其他任何地方捕获到Promise中的缺点,也便是说,window.onerror是无法捕获到promise中的缺点的。乃至纵然promise自身带有rejection处理函数,我们也该当手动去处理缺点。可以从下面的网站理解更多关于promise缺点处理的信息。http://www.html5rocks.com/en/tutorials/es6/promises/#toc-error-handling。举个例子:
我们可以利用 Protected Entry Points 来包装一些Promise的方法,在个中添加一个try/catch语句来处理缺点,利用这种方法可使使得我们捕获更多缺点信息。
var _oldPromiseThen = Promise.prototype.then;
Promise.prototype.then = function protectedThen(callback, errorHandler) {
return _oldPromiseThen.call(this, protectEntryPoint(callback), protectEntryPoint(errorHandler));
};
遗憾的是,默认情形下Promises中的缺点不会被捕获到
Error handling in Promise polyfills
一些Promise实现,比如Q, Bluebird 和 Closure,这些Promise实现在处理JS缺点时各有自己的办法,但是都比原生浏览器实现的Promise在处理缺点上表现出色。
在Q中,我们可以通过.done()来结束Pormise链,这样就担保了及时在Promise链中没有处理的缺点依然会被抛出,然后可以通过其他办法处理。可以通过如下地址理解更多关于Q处理JS缺点的信息。https://github.com/kriskowal/q#handling-errors在Bluebird中,没有处理的rejections会立即在掌握台打印和报出。拜会 http://bluebirdjs.com/docs/features.html#surfacing-unhandled-errors在Closure’s goog.Promise 的Promise实现中,(译者注,不理解,没翻译)unhandled rejections are logged and reported if no chain in the Promise handles the rejection within a configurable time interval (in order to allow code later in the program to add a rejection handler).Long stack traces
在 async stack trace 部分,我们已经谈论了浏览器并不会捕获异步hook中的发生的缺点的追溯栈信息,例如调用Promise.prototype.then时,一些Promise polyfills能够获取到异步缺点的追溯栈信息,也使得诊断缺点变得相对随意马虎。虽然这样做有些代价,但是我们可以从这些方法中获取到更多有用的信息。
在Q中,可以利用 Q.longStackSupport = true;. 拜会 https://github.com/kriskowal/q#long-stack-traces在Bluebird,在程序的某个地方调用Promise.longStackTraces() 。拜会 http://bluebirdjs.com/docs/features.html#long-stack-traces.在Closure中,把 goog.Promise.LONG_STACK_TRACES 设置为true。Web Workers
Web workers,包括dedicated workers、shared workers和service workers, 现在这些worker已经在运用程序中广泛被利用,由于所有的worker都是单独的JavaScript文件,因此他们该当有自己的缺点处理代码,推举的做法便是每个worker文件又该当有自己的缺点处理和报告的脚本,这样就能够更加高效的处理workers中的缺点了。
Dedicated workers
Dedicated web workers 在不同于主文件的其余一个高下文环境中运行,因此上面阐述的那些捕获缺点的机制都不能够捕获Dedicated web workers中的缺点,因此我须要采纳一些额外的手段来捕获worker中的缺点。
当我们天生一个worker时,我们可以吧onerror属性设置到worker上面,如下:
var worker = new Worker('worker.js');
worker.onerror = function(errorEvent) { ... };
这样做可以从下面的网站找到根据, https://html.spec.whatwg.org/multipage/workers.html#handler-abstractworker-onerror.这和window.onerror有所不同的是,我们把onerror绑定到了worker上面,同时,监听的函数也不再接管五个参数,而是只有一个errorEvent工具作为参数。这个缺点工具上面的API可以参考 https://developer.mozilla.org/en-US/docs/Web/API/ErrorEvent.这个工具包括缺点信息、文件名、缺点行数、缺点列数,但是并没有追溯栈了(也便是errorEvent.error是null),由于这个API是在父文件中实行,因此我们也可以采纳父文件中的发送缺点机制来发送worker中的缺点,但是遗憾的是,由于这个缺点工具没有追溯栈,因此这个API利用也受到了限定。
在worker运行内部,我们也可以定义一个类似常规的window.onerror的API,拜会,https://html.spec.whatwg.org/multipage/webappapis.html#onerroreventhandler.
self.onerror = function(message, filename, line, col, error) { ... };
关于self.onerror这个API的谈论可以参上上面关于window.onerror的谈论。然后,仍旧有两点须要把稳:
self.onerror中,FireFox和Safari在self.onerror的回调函数中不会有第五个参数,因此,在这连个浏览器中也就无法从worker缺点中获取追溯栈(Chrome 和 IE11 能够获取到追溯栈),但是我们依然可以通过Protected Entry Points 对onmessage 函数进行包装,然后我们就能够在Firefox和Safari中获取到worker 缺点的追溯栈了。
由于缺点捕获代码在worker中实行,因此我们该当选择怎么把缺点发送到缺点搜集做事器中,我们可以选择postMessage 把缺点信息发送给父级页面,或者直接在worker中通过XHR把缺点直接报告给缺点网络的做事器。
须要把稳的是,在Firefox、Safari和IE11(不包括Chrome),父级页面中window.onerror在worker脚本中的onerror注册监听函数被调用后,依然会被调用,但是,父级页面中的window.onerror捕获的缺点工具并不会包含追溯栈,我们也该当把稳的是,不应该把相同的缺点重复发送到做事器。
Shared workers
Chrome和Firefox支持ShareWorker API,这样worker就可以在多个页面共享了,由于worker是共享的,因此该worker也不从属与某一个父级页面,这也就导致了缺点处理办法的不同,ShareWorker 常日可以采纳和dedicated web worker相同的缺点处理办法。
在Chrome中,当ShareWorker涌现JS缺点时,只有worker内部的缺点捕获代码能够被实行(比如self .onerror),父级页面中的window.onerror不会被实行,同时Chrome还不支持虽然已在规范中定义了的AbstracWorker.onerror。.
在Firefox,行为又有些不同,worker中的缺点会使得父级页面的window.onerror的监听函数也被调用,但是虽然父级页面也能捕获到缺点,依然短缺第五个参数,也便是说捕获到的缺点工具上面没有追溯栈,因此这也会有利用上的限定。
shared workers的缺点处理在浏览期间差异性很大
Service Workers
Service Workers是新规范中提出的,现目前仅在Chrome和Firefox最近版本中实现,该worker和dedicated web worker的缺点处理机制差不多。
Service workers是通过调用navigator.serviceWorker.register 开引入的,该方法返回一个Promise,当service worker引入失落败,该Promise就会被reject掉。如果引入失落败,那么在Service worker初始化时就会抛出一个缺点,该缺点仅包含一条缺点信息。除此之外,由于Promise不会把缺点暴露给window.onerror 事宜监听函数,因此我们须要给上面方法返回的Promise添加一个catch代码块,用来捕获该Promise中抛出的缺点。
navigator.serviceWorker.register('service-worker-installation-error.js').catch(function(error) {
// error typeof string
});
和其他workers一样,service worker也可以设置self.onerror来捕获缺点,service worker初始化缺点会被self.onerror不会,但是遗憾的是,捕获的缺点依然没有第五个参数,也便是没有追溯栈。
service worker API从AbstractWorker 接口上继续了onerror 属性,但是遗憾的是,Chrome并不支持该属性。
Worker Try/Catch
为了能够在Firefox和Safari浏览器的worker中捕获到追溯栈,onmessage监听函数内部可以通过一个try/catch 代码块包围,这样就可以捕获仍和冒泡上来的缺点了。
self.onmessage = function(event) { try { // logic here } catch (e) { // Report exception. }};
常规的try/catch 代码块能够捕获这些缺点中的追溯栈,举个例子,产生缺点的追溯栈如下:
Error from workerthrowError@http://mknichel.github.io/javascript-errors/worker.js:4:9throwErrorWrapper@http://mknichel.github.io/javascript-errors/worker.js:8:3self.onmessage@http://mknichel.github.io/javascript-errors/worker.js:14:7
Chrome Extensions
由于Chrome Extensions 不同的Chrome 扩展缺点的表现也有所不同,因此他们该当有自己处理缺点的办法,同时,Chrome 扩展中的缺点在大型项目中的危害也不容小觑的。
Content Scripts
所谓的Content script便是当用户访问网站时,这些脚本在一个相对独立的实行环境中运行,可以在这些script中操作DOM,但是却不能够获取到网站中的其它JavaScript脚本。
由于content scripts有他们独立的实行环境,因此也可以利用window.onerror来捕获Content script中的缺点,但是遗憾的是,在content script中通过window.onerror捕获的缺点会被标记为”Script error”。没有文件名,行数和列数也被标记为0.可以通过以下网站理解 https://code.google.com/p/chromium/issues/detail?id=457785. 在这bug被办理之前,我们依然可以通过try/catch语句或者protected entry points来捕获Content script中带有追溯栈的JS缺点。
在很多年前,Content script中的缺点还会被父级网页中的window.onerror捕获到,这样就导致了父级网页中捕获到很多垃圾的缺点信息,这一bug在2013年后期已被修复。(https://code.google.com/p/chromium/issues/detail?id=225513).
Chrome 扩展中的JS缺点该当在被window.onerror捕获之前被过滤掉
Browser Actions
Chrome扩展可以产生一个弹出窗口,这些弹出窗口是一个小型的HTML文件,有用户点击URL栏右边的Chrome 扩展图标所致。这些弹出窗口可以在一个完备不同的环境中实行JavaScript代码,window.onerror也会捕获到这些窗口产生的缺点。
Reporting Errors to the Server
一旦客户端将带有精确的追溯栈的JS缺点捕获到后,这些缺点该当发回缺点处理做事器,以便进一步对缺点进行追踪、剖析、和肃清缺点。常日吧缺点发送到做事器是通过XHR来完成的,发送到做事器的缺点包括:缺点信息、追溯栈以及其他客户端和缺点干系的信息,比如运用程序所用框架的版本号,用户代理(user agent),用户的地址,以及网页的URL。
如果运用程序利用了多种机制来捕获缺点,那么该当把稳的地方便是不要把相同的缺点发送两次,同时,发送的缺点信息末了带有一个追溯栈,这样在大型运用程序中才能够更好的找出问题根源。