如何在 zone.js 中打印当前区域的路径

How to print path to the current Zone in zone.js

我正在试验区域 (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> => zoneA => zoneB.

但是从输出中看并不明显。只有 [root]zoneB,它没有提到令人困惑的 zoneA。我猜这是因为 zone.js 的猴子补丁仅将区域信息添加到调用堆栈中的行。因此,当我使用 setTimeout() 而不是创建 zoneA 时,它与输出中的任何行都不对应,这就是为什么我在任何地方都看不到它的原因。

尽管如此,我可以通过迭代所有它的父级来打印到当前区域的路径,但这意味着我需要知道错误首先发生的位置并向其中添加以下代码(这在实践中会非常乏味):

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 并且比这更容易。

要获取 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>