最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to print path to the current Zone in zone.js - Stack Overflow

programmeradmin3浏览0评论

I'm experimenting with zones (zone.js) and I realized I don't know what's the best way to print all the zones from root to the current zone that threw an error.

For example this code uses two nested callbacks with setTimeout() and then calls a function called failedFunc() that throws an error:

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();

When I run this example it gives the following output:

/.../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>]

The correct path for the zone that threw the error is <root> => zoneA => zoneB.

However it's not obvious from the output. There's just [root] and zoneB and it doesn't mention the zoneA which is confusing. I guess this is because the zone.js's monkey patch only adds zone info to the lines in the call stack. So when I'm using setTimeout() than creating zoneA doesn't correspond to any line in the output and that's why I don't see it anywhere.

Nonetheless, I can print the path to the current zone by iterating all it's parents but this means I need to know where the error first happened and add the following code to it (which would be very tedious in practice):

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");
}

// ...

Now when I run this I'll get what I need:

[ 'zoneB', 'zoneA', '<root>' ]

/.../zone-test/node_modules/zone.js/dist/zone-node.js:170
                        throw error;
                        ^
Error: it's broken
    at new Error (native)

So I'm wondering how to use zone.js in practice and in a way that it's easier than this.

I'm experimenting with zones (zone.js) and I realized I don't know what's the best way to print all the zones from root to the current zone that threw an error.

For example this code uses two nested callbacks with setTimeout() and then calls a function called failedFunc() that throws an error:

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();

When I run this example it gives the following output:

/.../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>]

The correct path for the zone that threw the error is <root> => zoneA => zoneB.

However it's not obvious from the output. There's just [root] and zoneB and it doesn't mention the zoneA which is confusing. I guess this is because the zone.js's monkey patch only adds zone info to the lines in the call stack. So when I'm using setTimeout() than creating zoneA doesn't correspond to any line in the output and that's why I don't see it anywhere.

Nonetheless, I can print the path to the current zone by iterating all it's parents but this means I need to know where the error first happened and add the following code to it (which would be very tedious in practice):

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");
}

// ...

Now when I run this I'll get what I need:

[ 'zoneB', 'zoneA', '<root>' ]

/.../zone-test/node_modules/zone.js/dist/zone-node.js:170
                        throw error;
                        ^
Error: it's broken
    at new Error (native)

So I'm wondering how to use zone.js in practice and in a way that it's easier than this.

Share Improve this question asked Mar 24, 2017 at 9:26 martinmartin 97.1k26 gold badges204 silver badges236 bronze badges 2
  • Zonejs uses the concept of ZoneFrame to get such output.github./angular/zone.js/blob/v0.8.5/lib/zone.ts#L1656-L1676. You can write your own version of global.Error.As i noticed this output is changed very often. Check last mit github./angular/zone.js/mit/… – yurzui Commented Apr 13, 2017 at 13:38
  • I think you're looking for longStackTraceZone, I changed your code a little bit and created jsFiddle: jsfiddle/Oski/ye0yz8c4/2 I couldn't find long-stack-trace-zone so I just pasted it in HTML section. Zone.current always returns the zone in which it's being run – Oskar Commented Apr 13, 2017 at 14:30
Add a ment  | 

1 Answer 1

Reset to default 8 +75

To obtain the full stacktrace of your zone you have to use long-stack-trace-zone

Please note, that I'm throwing an exception, this is why you will see an error in my snippet. The question and the answer is about printing full stacktrace:

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./ajax/libs/zone.js/0.8.5/zone.min.js"></script>
<!--  https://raw.githubusercontent./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>

发布评论

评论列表(0)

  1. 暂无评论