using zone.js hooks in node

2020-07-18 02:24发布

问题:

I'm trying to write a simple demo using angular/zone.js in node, but for some reason neither the beforeTask or afterTask are being called.

Here is the code I'm running:

require('zone.js');

function foo () {
  Zone.current.fork({
    name: 'foo_zone',
    
    beforeTask: function () {
      console.log('~~~ ZONE START ~~~');
    },
    
    afterTask: function () {
      console.log('~~~ ZONE END ~~~');
    }
  })
    .run(function () {
      console.log('in the zone');
      console.log('Zone.current.name', Zone.current.name); // prints foo_zone
      setTimeout(() => {
        console.log('timeout is up');
      }, 1000);
    });
}
foo();

Now inside the zone everything prints fine, including the zone name, but neither of the hooks are called.

Am I missing something basic with zone.js + node.js?

(running with node v5.0.0, zone.js 0.6.23)

回答1:

Here is the sample repository. https://github.com/JiaLiPassion/zone-node

first, you need to use the latest version of zone.js and to use zone.js in nodejs, you should require zone-node.js, the following is a running sample.

require('./zone-node.js');

function log(str) {
  Zone.root.run(function() {
    console.log(str);
  });
}
function foo() {
  Zone.current.fork({
    name: 'fooZone', 
    onScheduleTask: function(delegate, curr, target, task) {
      log('Zone begin to schedule task not async yet ' + task.source);
      return delegate.scheduleTask(target, task);
    },
    onInvokeTask: function(delegate, curr, target, task, applyThis, applyArgs) {
      log('~~~~Zone before invoke async callback~~~~' + task.source);
      delegate.invokeTask(target, task, applyThis, applyArgs);
      log('~~~~Zone after invoke async callback~~~~' + task.source);
    },
  }).run(function() {
    log('current zone, ' + Zone.current.name);
    setTimeout(function() {
      log('timeout is up, ', Zone.current.name);
    }, 100);
  });
};

foo();

and after run in nodejs, the output will be.

current zone, fooZone
Zone begin to schedule task not async yetsetTimeout
~~~~Zone before invoke async callback~~~~setTimeout
timeout is up,
~~~~Zone after invoke async callback~~~~setTimeout


回答2:

I ran into this same issue. If you were like me you probably saw one of the examples in the zone.js repo like this one and saw the hooks beforeTask and afterTask being used. However if you look at the API and look at the ZoneSpec interface (which specifies the hooks that zone.fork will recognize) there is no mention of beforeTask or afterTask anywhere. This is likely because the hooks have been renamed/refactored since the time that example was written and it just hasn't been updated

However, there is a hook mentioned in the API named "onInvokeTask" defined as:

onInvokeTask?: (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, task: Task, applyThis: any, applyArgs: any) => any;

which will be called in place of a task being invoked when given in the ZoneSpec, so I tried something like this:

require('zone.js');

function foo () {
  Zone.current.fork({
    name: 'foo_zone',

    onInvokeTask: function (parentZoneDelegate, currentZone, targetZone, task, applyThis, applyArgs) {
      console.log('~~~ ZONE START ~~~');
      parentZoneDelegate.invokeTask(targetZone, task);
      console.log('~~~ ZONE END ~~~');
    },
  })
    .run(function () {
      setTimeout(function() {
        console.log('in the zone');
        console.log('Zone.current.name', Zone.current.name); // prints foo_zone
        setTimeout(() => {
          console.log('timeout is up');
        }, 1000);
      }, 0);
    });
}
foo();

which prints the desired result:

~~~ ZONE START ~~~
in the zone
Zone.current.name foo_zone
~~~ ZONE END ~~~
~~~ ZONE START ~~~
timeout is up
~~~ ZONE END ~~~

A few things to note:

  1. Unlike the beforeTask and afterTask in the example which appear to be called before and after a task is run, the onInvokeTask hook is called in place of running a task, so you have to specify to run the task in that hook if you want the task to run, hence the parentZoneDelegate.invokeTask(targetZone, task);

  2. I wrapped the code inside your run function in setTimeout(function() { ... }, 0) because the code inside your run function is actually called in the same task as all of the code in your example (except for the code in your setTimeout call which is run in a new task) and the onInvokeTask hook doesn't apply to the current task since the current task has already been invoked. This means that ~~~ ZONE START ~~~ and ~~~ ZONE END ~~~ would only be printed around the timeout is up line.