Friday, March 17, 2017

Zonejs Overview with Example


Zonejs is one of the core library used in Angularjs 2. Zonejs is to maintain contextual execution for single or multi-leveled asynchronous methods. So, it means it helps to keep track of the parent context of currently executing asynchronous method.

Example-

Zone.current.fork({}).run(function(){
 Zone.current.myZoneVar = true;
 console.log('Assigned myZoneVar');
 setTimeout(()=>{
   console.log('In timeout', Zone.current.myZoneVar);
 },1000);
});
console.log('Out side', Zone.current.myZoneVar);


Here we created a fork of our current Zone and run is invoking the method under the Zone. The method has an asynchronous call (setTimeout). But as it is under zone we have the access of Zone variable. In last line we can see out of zone we are trying to access same variable, but it will have undefined in it.

Forking a zone will basically inheriting an existing context and you can override it if required.

Example-

function main(){
 console.log('Start ' );
 setTimeout(function(){
 throw new Error('Oops End- Error');},1000);
 console.log('In Progress ');
}

Zone.current.fork({
  onHandleError: (parentZoneDelegate, currentZone, targetZone, error) =>{
    console.log('error handler ->',error)
  }
}).run(main);


Here, we are overriding current zone error handler using onHandleError.

State changes tracking of context using interception very easy using zone events handlers.

List of events-

/**
* Allows the interception of zone forking.
*
* When the zone is being forked, the request is forwarded to this method for interception.
*
* @param parentZoneDelegate Delegate which performs the parent [ZoneSpec] operation.
* @param currentZone The current [Zone] where the current interceptor has beed declared.
* @param targetZone The [Zone] which originally received the request.
* @param zoneSpec The argument passed into the `fork` method.
*/
onFork?: (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, zoneSpec: ZoneSpec) => Zone;
/**
* Allows interception of the wrapping of the callback.
*
* @param parentZoneDelegate Delegate which performs the parent [ZoneSpec] operation.
* @param currentZone The current [Zone] where the current interceptor has beed declared.
* @param targetZone The [Zone] which originally received the request.
* @param delegate The argument passed into the `warp` method.
* @param source The argument passed into the `warp` method.
*/
onIntercept?: (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, delegate: Function, source: string) => Function;
/**
* Allows interception of the callback invocation.
*
* @param parentZoneDelegate Delegate which performs the parent [ZoneSpec] operation.
* @param currentZone The current [Zone] where the current interceptor has beed declared.
* @param targetZone The [Zone] which originally received the request.
* @param delegate The argument passed into the `run` method.
* @param applyThis The argument passed into the `run` method.
* @param applyArgs The argument passed into the `run` method.
* @param source The argument passed into the `run` method.
*/
onInvoke?: (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, delegate: Function, applyThis: any, applyArgs: any[], source: string) => any;
/**
* Allows interception of the error handling.
*
* @param parentZoneDelegate Delegate which performs the parent [ZoneSpec] operation.
* @param currentZone The current [Zone] where the current interceptor has beed declared.
* @param targetZone The [Zone] which originally received the request.
* @param error The argument passed into the `handleError` method.
*/
onHandleError?: (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, error: any) => boolean;
/**
* Allows interception of task scheduling.
*
* @param parentZoneDelegate Delegate which performs the parent [ZoneSpec] operation.
* @param currentZone The current [Zone] where the current interceptor has beed declared.
* @param targetZone The [Zone] which originally received the request.
* @param task The argument passed into the `scheduleTask` method.
*/
onScheduleTask?: (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, task: Task) => Task;
onInvokeTask?: (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, task: Task, applyThis: any, applyArgs: any) => any;
/**
* Allows interception of task cancelation.
*
* @param parentZoneDelegate Delegate which performs the parent [ZoneSpec] operation.
* @param currentZone The current [Zone] where the current interceptor has beed declared.
* @param targetZone The [Zone] which originally received the request.
* @param task The argument passed into the `cancelTask` method.
*/
onCancelTask?: (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, task: Task) => any;
/**
* Notifies of changes to the task queue empty status.
*
* @param parentZoneDelegate Delegate which performs the parent [ZoneSpec] operation.
* @param currentZone The current [Zone] where the current interceptor has beed declared.
* @param targetZone The [Zone] which originally received the request.
* @param isEmpty
*/
onHasTask?: (delegate: ZoneDelegate, current: Zone, target: Zone, hasTaskState: HasTaskState) => void;

Zone js can be used for any js app. It's just a helper library for implementing contextual execution for asynchronous methods. Bellow we can see, we can implement error stack trace using Zone.
Handler details created in longStackTraceZoneSpec custom property of Zone. See the running example code.

Example-

function grandChild(){
 console.log('set grandchild');
 setTimeout(function(){ throw new Error('Error--');},1000);
}

function child(){
 console.log('set child');
 grandChild();
}

function parent(){
 console.log('set parent');
 child();
}

function start(){
 parent();
}
var forkVal = Zone.longStackTraceZoneSpec;
/*forkVal.onHandleError= function (parentZoneDelegate, currentZone, targetZone, error) {
console.log('error handler ->',error)
};*/
//Uncomment upper section to see default error with out longStackTraceZoneSpec---|
Zone.current.fork(forkVal).run(start);

// see the console... You will see full error stack trace with method name ref...


The last example is to get the total time count for nested asynchronous call using zone. As the bootstrap method is under zone context, Zone variables and functions will be accessible to all asynchronous call under parent /root zone. This is the core flavor of Zone.



To conclude, we can say " Zone is an execution context that persists across async tasks. You can think of it as thread-local storage for JavaScript VMs." 
Angular 2 is utilizing Zonejs for change detection. Whenever any change happens, it is detected by following code in Angular 2 - 
ObservableWrapper.subscribe(this.zone.onTurnDone, () => {
  this.zone.run(() => {
    this.tick();
  });
});

tick() {
  // perform change detection
  this.changeDetectorRefs.forEach((detector) => {
    detector.detectChanges();
  });
}
Angular zone emits onTrunDone event to start change detection in the app.

Ref to Angular2 Repo- Zone_Start

Further study -



No comments: