Zone.js deep diving - Execution Context
Published: 2020-02-18 02:21:19

---
title: Zone.js deep diving - Execution Context
published: true
date: 2020-01-28 22:22:45 UTC
tags: 
canonical_url: https://www.thisdot.co/blog/zone-js-deep-diving-execution-context
---

# Zone.js deep diving

## Chapter 1: Execution Context

As an Angular developer, you may know `NgZone`, which is a service for executing work inside, or outside of the `angular Zone`. You may also know that this `NgZone` service is based on a library called `zone.js`, but most developers may not directly use the APIs of `zone.js`, or know what `zone.js` is, so I would like to use several articles to explain `zone.js` to you.

My name is `Jia Li`. I am a senior software engineer at This Dot Labs, and I have contributed to `zone.js` for more than 3 years. Now, I am the code owner of `angular/zone.js` package (zone.js had been merged into `angular monorepo`), and I am also an Angular collaborator.

### What is Zone.js

`Zone.js` is a library created by [Brian Ford](https://twitter.com/briantford) in 2010 and is inspired by [Dart](https://dart.dev/articles/archive/zones). It provides a concept called `Zone`, which is an **execution context** that persists across async tasks.

A `Zone` can:

1. Provide execution context that persist across async tasks.
2. Intercept async task, and provide life cycle hooks.
3. Provide centralized error handler for async tasks.

We will discuss those topics one by one.

#### Execution Context

So what is `Execution Context`? This is a fundamental term in Javascript. `Execution Context` is an abstract concept that holds information about the environment within the current code being executed. The previous sentence may be a little difficult to understand without context, so let's use some code samples to explain it. For better understanding of `Execution Context/Scope`, please refer to this great book from [getify](https://github.com/getify/You-Dont-Know-JS/tree/2nd-ed/scope-closures)

1. Global Context

```
const globalThis = this;
let a = 0;

function testFunc() {
  let b = 0;
  console.log('this in testFunc is:', this === globalThis);
}

testFunc();

```

So in this first example, we have a `global execution context`, which will be created before any code is created. It needs to know it's `scope`, which means the `execution context` needs to know which variables and functions it can access. In this example, the global execution context can access variable `a`. Then, after the scope is determined, the Javascript engine will also determine the value of `this`. If we run this code in `Browser`, the `globalThis` will be `window`, and it will be `global` in `NodeJS`.

Then, we execute `testFunc`. When we are going to run a new function, a new `execution context` will be created, and again, it will try to decide the `scope` and the value of `this`. In this example, the `this` in the function `testFunc` will be the same with `globalThis`, because we are running the `testFunc` without assigning any `context object` by using `apply/call`. And the `scope` in `testFunc` will be able to access both `a` and `b`.

This is very simple. Let's just see another example to recall the Javascript 101.

```
const testObj = {
  testFunc: function() {
    console.log('this in testFunc is:', this);
  }
};

// 1. call testFunc with testObj
testObj.testFunc();

const newTestFunc = testObj.testFunc;
// 2. call newTestFunc who is referencing from testObj.testFunc
newTestFunc();

const newObj = {};
// 3. call newTestFunc with apply
newTestFunc.apply(newObj);

const bindObj = {};
const boundFunc = testObj.testFunc.bind(bindObj);
// 4. call bounded testFunc
boundFunc();
boundFunc.apply(somethingElse);

```

Here, `testFunc` is a property of `testObj`. We call `testFunc` in several ways.We will not go very deeper about how it works. We just list the results here. Again, please check [getify](https://github.com/getify/You-Dont-Know-JS/tree/2nd-ed/scope-closures) for more details.

1. call `testObj.testFunc`, `this` will be `testObj`.
2. create a reference `newTestFunc`, `this` will be `globalThis`.
3. call with `apply`, `this` will be `newObj`.
4. call `bounded version`, `this` will always be `bindObj`.

So we can see that `this` will change depending on how we call this function. This is a very fundamental mechanism in Javascript.

So, back to `Execution Context` in `Zone`. What is the difference?Let's see the code sample here:

```
const zoneA = // create a new zone ...;
zoneA.run(function() {
  // function is in the zone
  // just like `this`, we have a zoneThis === zoneA
  expect(zoneThis).toBe(zoneA);
  setTimeout(function() {
    // the callback of async operation
    // will also have a zoneThis === zoneA
    // which is the zoneContext when this async operation
    // is scheduled.
    expect(zoneThis).toBe(zoneA);
  });
  Promise.resolve(1).then(function() {
    // all async operations will be in the same zone
    // when they are scheduled.
    expect(zoneThis).toBe(zoneA);
  });
});

```

So, in this example, we created a `zone` (we will talk about how to create a `zone` in the next chapter). As suggested by the term `zone`, when we run a function inside the `zone`, suddenly we have a new `execution context` provided by `zone`. Let's call it `zoneThis` for now. Unlike `this`, the value of `zoneThis` will always equal the `zone`, where the functions is being executed in no matter if it is a `sync` or an `async` operation.

You can also see, in the callback of `setTimeout`, that the `zoneThis` will be the same value when `setTimeout` is scheduled. So this is another principle of Zone. The zone execution context will be kept as the same value as it is scheduled.

So you may also wonder how to get `zoneThis`. Of course, we are not inventing a new Javascript keyword `zoneThis`, so to get this `zone context`, we need to use a static method, introduced by `Zone.js`, which is `Zone.current`.

```
const zoneA = // create a new zone ...;
zoneA.run(function() {
  // function is in the zone
  // just like `this`, we have a Zone.current === zoneA
  expect(Zone.current).toBe(zoneA);
  setTimeout(function() {
    // the callback of async operation
    // will also have a Zone.current === zoneA
    // which is the zoneContext when this async operation
    // is scheduled.
    expect(Zone.current).toBe(zoneA);
  });

```

Because there is a `Zone execution context` we can share inside a `zone`, we can also share some data.

```
const zoneA = Zone.current.fork({
  name: 'zone',
  properties: {key: 'sharedData'}
});
zoneA.run(function() {
  // function is in the zone
  // we can use data from zoneA
  expect(Zone.current.get('key')).toBe('sharedData');
  setTimeout(function() {
    // the callback of async operation
    // we can use data from zoneA
    expect(Zone.current.get('key')).toBe('sharedData');
  });

```

`Execution Context` is the fundamental feature of `Zone.js`. Based on this feature, we can monitor/track/intercept the lifecycle of async operations. We will talk about those hooks in the next chapter.

_This Dot Inc. is a consulting company which contains two branches : the media stream, and labs stream. This Dot Media is the portion responsible for keeping developers up to date with advancements in the web platform. This Dot Labs provides teams with web platform expertise, using methods such as mentoring and training._