我正在试验区域(zone.js),我意识到我不知道从根目录到当前区域打印所有区域的最佳方式是什么错误。
例如,此代码使用两个嵌套回调setTimeout()
,然后调用一个名为failedFunc()
的函数抛出错误:
require('zone.js');
function failedFunc() {
throw new Error("it's broken");
}
let rootZone = Zone.current;
function func1() {
let zoneA = rootZone.fork({name: 'zoneA'});
zoneA.run(() => {
setTimeout(() => func2());
});
}
function func2() {
let zoneB = Zone.current.fork({name: 'zoneB'});
zoneB.run(() => {
setTimeout(() => failedFunc());
});
}
func1();
当我运行此示例时,它提供以下输出:
/.../zone-test/node_modules/zone.js/dist/zone-node.js:170
throw error;
^
Error: it's broken
at new Error (native)
at failedFunc (/.../zone-test/zone_02.js:12:9) [zoneB]
at Timeout.setTimeout (/.../zone-test/zone_02.js:28:22) [zoneB]
at Zone.runTask (/.../zone-test/node_modules/zone.js/dist/zone-node.js:166:47) [<root> => zoneB]
at Timeout.ZoneTask.invoke (/.../zone-test/node_modules/zone.js/dist/zone-node.js:416:38) [<root>]
at Timeout.data.args.(anonymous function) [as _onTimeout] (/.../zone-test/node_modules/zone.js/dist/zone-node.js:1590:25) [<root>]
at ontimeout (timers.js:365:14) [<root>]
at tryOnTimeout (timers.js:237:5) [<root>]
at Timer.listOnTimeout (timers.js:207:5) [<root>]
引发错误的区域的正确路径为<root>
=&gt; zoneA
=&gt; zoneB
。
然而,输出并不明显。只有[root]
和zoneB
并且它没有提到令人困惑的zoneA
。我想这是因为zone.js
的猴子补丁只会将区域信息添加到调用堆栈中的行。因此,当我使用setTimeout()
而非创建zoneA
并不对应输出中的任何行时,这就是为什么我在任何地方都看不到它。< / p>
尽管如此,我可以通过迭代所有它的父母来打印当前区域的路径,但这意味着我需要知道错误发生的位置并将以下代码添加到其中(这在实践中非常繁琐) ):
function failedFunc() {
let zone = Zone.current;
let zones = [];
while (zone) {
zones.push(zone.name);
zone = zone.parent;
}
console.log(zones);
throw new Error("it's broken");
}
// ...
现在,当我运行这个时,我会得到我需要的东西:
[ 'zoneB', 'zoneA', '<root>' ]
/.../zone-test/node_modules/zone.js/dist/zone-node.js:170
throw error;
^
Error: it's broken
at new Error (native)
所以我想知道如何在实践中使用zone.js,并且比这更容易。
答案 0 :(得分:8)
要获得zone
的完整堆栈跟踪,您必须使用long-stack-trace-zone
请注意,我正在抛出异常,这就是为什么你会在我的代码段中看到错误的原因。问题和答案是关于打印完整的堆栈跟踪:
function failedFunc() {
throw new Error("it's broken");
}
function func1() {
let zoneA = Zone.current.fork({
name: 'zoneA'
});
zoneA.run(function() {
setTimeout(function() {
func2()
});
});
}
function func2() {
let zoneB = Zone.current.fork({
name: 'zoneB'
});
zoneB.run(function() {
setTimeout(function() {
failedFunc()
});
});
}
Zone.current.fork({
onHandleError: function(parentZoneDelegate, currentZone, targetZone, error) {
console.log(error.stack);
}
}).fork(Zone.longStackTraceZoneSpec).run(func1);
<script src="https://cdnjs.cloudflare.com/ajax/libs/zone.js/0.8.5/zone.min.js"></script>
<!-- https://raw.githubusercontent.com/angular/zone.js/master/dist/long-stack-trace-zone.min.js -->
<script>
!function(t,a){"object"==typeof exports&&"undefined"!=typeof module?a():"function"==typeof define&&define.amd?define(a):a()}(this,function(){"use strict";function t(){return new Error(u)}function a(){try{throw t()}catch(a){return a}}function e(t){return t.stack?t.stack.split(i):[]}function n(t,a){for(var n=e(a),r=0;r<n.length;r++){var c=n[r];s.hasOwnProperty(c)||t.push(n[r])}}function r(t,a){var e=[a.trim()];if(t)for(var r=(new Date).getTime(),c=0;c<t.length;c++){var o=t[c],s=o.timestamp,f="____________________Elapsed "+(r-s.getTime())+" ms; At: "+s;f=f.replace(/[^\w\d]/g,"_"),e.push(h.replace(_,f)),n(e,o.error),r=s.getTime()}return e.join(i)}function c(t,a){a>0&&(t.push(e((new l).error)),c(t,a-1))}function o(){var t=[];c(t,2);for(var a=t[0],e=t[1],n=0;n<a.length;n++){var r=a[n];if(r.indexOf(u)==-1){var o=r.match(/^\s*at\s+/);if(o){h=o[0]+_+" (http://localhost)";break}}}for(var n=0;n<a.length;n++){var r=a[n],i=e[n];if(r!==i)break;s[r]=!0}}var i="\n",s={},f="__creationTrace__",u="STACKTRACE TRACKING",_="__SEP_TAG__",h=_+"@[native]",l=function(){function t(){this.error=g(),this.timestamp=new Date}return t}(),d=t(),k=a(),g=d.stack?t:k.stack?a:t;Zone.longStackTraceZoneSpec={name:"long-stack-trace",longStackTraceLimit:10,getLongStackTrace:function(t){if(t){var a=t[Zone.__symbol__("currentTask")],e=a&&a.data&&a.data[f];return e?r(e,t.stack):t.stack}},onScheduleTask:function(t,a,e,n){var r=Zone.currentTask,c=r&&r.data&&r.data[f]||[];return c=[new l].concat(c),c.length>this.longStackTraceLimit&&(c.length=this.longStackTraceLimit),n.data||(n.data={}),n.data[f]=c,t.scheduleTask(e,n)},onHandleError:function(t,a,e,n){var c=Zone.currentTask||n.task;if(n instanceof Error&&c){var o=r(c.data&&c.data[f],n.stack);try{n.stack=n.longStack=o}catch(i){}}return t.handleError(e,n)}},o()});
</script>