Learn basic Zone.js by examples

@JiaLiPassion

Who am I

  • Name: Jia Li
  • Company: ThisDot
  • Zone.js: Code Owner
  • Angular: Collaborator

Agenda

  • What's Zone.js
  • When and why you need Zone.js
  • Zone.js in Angular

What is Zone.js

A Zone is an execution context that persists across async tasks.

Created by Brian Ford inspired by Dart.

What zone.js can do

  • Provide execution context

  • Provide async task lifecycle hook

  • Provide error handler for async operations

Execution context in zone.js

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

Async Error Handling

Zone.current.fork(
  {
    name: 'error',
    onHandleError: (delegate, curr, target, error) => {
       logger.error(error);
       return delegate.handleError(target, error);
    }
}).runGuarded(() => {
    setTimeout(() => {
       throw new Error('timeout error');
    });
    setTimeout(() => {
       throw new Error('another timeout error');
    });
});

When should we use Zone

  • Test
    • Sync(Disallow Async)
    • Async(Auto done, Auto cleanup)
    • FakeAsync()
  • Debug
    • LongStackTrace
    • Task Tracing
  • Performance measure
  • Framework AutoRender
  • User Action Tracing
  • Resource Releasing

Demo: LongStackTrace

  function main () {
    b1.addEventListener('click', bindSecondButton);
  }

  /*
   * What if your stack trace could tell you what
   * order the user pushed the buttons from the stack trace?
   * What if you could log this back to the server?
   * Think of how much more productive your debugging could be!
   */
  function bindSecondButton () {
    b2.addEventListener('click', throwError);
  }


  function throwError () {
    throw new Error('aw shucks');
  }

  main();

Demo: Tracking: Counting

    function btnClicked () {
        recurRandonGenerateTimeout(10);
    }

    function recurRandonGenerateTimeout (x) {
      if (x > 0) {
        setTimeout(function () {
          for (var i = x; i < 8; i++) {
            recur(x - 1, Math.random()*100);
          }
        }, t);
      }
    }

Performance Profiling

    function btnClicked () {
        asyncHeavyWork1();
        asyncHeavyWork2();
        asyncHttpRequest();
    }

Auto releasing

const fs = require('fs');

fs.open('./test.txt', 'r', (err, fd) => {
  if (err) throw err;
  fs.fstat(fd, (err, stat) => {
    if (err) throw err;
    doSomething(fd, err => {});
    doSomethingElse(fd, err => {});
  });
});

const autoReleaseFSZone = Zone.current.fork({
  name: 'releaseFS',
  onHasTask: (pd, curr, target, hasTaskState) => {
    if (!hasTaskState.macroTask && !hasTaskState.microTask && fd !== -1) {
      fs.close(fd, (err) => {
        if (err) throw err;
        fd = -1;
      });
    }
    return pd.hasTask(target, hasTaskState);
  }
});

User Action Tracking

viewBtnClicked() {
  httpRequest(viewUrl);
  httpRequest(additionalInfoUrl);
}

orderBtnClicked() {
  httpRequest(orderUrl);
  httpRequest(transactionUrl);
}

errorBtnClicked() {
  throw new Error();
}

UI Auto Rendering

  function httpBtnClicked() {
    httpRequestUrl(viewUrl);
  }

  function timeoutBtnClicked() {
    setTimeout(() => {
      data.timeout = 'timeout';
    });
  }

  function addBtnClicked() {
    if (!data.num) {
      data.num = 0;
    }
    data.num ++;
  }

Async Test

const api = require('./async-lib');

describe('testAsync', () => {
  it('test async operation', (done) => {
    let a = 0;
    api.testAsync(a, r => {
      expect(r).toBe(1);
      done();
    });
  });
});
const api = require('./async-lib');

describe('testAsync', async(() => {
  it('test async operation', () => {
    let a = 0;
    api.testAsync(a, r => {
      expect(r).toBe(1);
    });
  });
}));

fakeAsync Test

describe('testAsync', () => {
  it('test long async operation', (done) => {
    setTimeout(() => {
      // ... expect something.
      done();
    }, 10000);
  });
});
describe('testAsync', () => {
  it('test long async operation', fakeAsync(() => {
    setTimeout(() => {
      // ... expect something.
    }, 10000);
    tick(10000);
  }));
});

Zone.js in Angular

NgZone

Tell when to trigger Change Detection

AsyncTest

FakeAsyncTest

SyncTest

Error Handling

Debug/Tracing

TaskTrackingZone

LongStackTraceZone

ngZone

ngZone.run(() => {
  // will be in angular zone
  // will trigger change detection
});

ngZone.runOutsideAngular(() => {
  // will be outside angular zone
  // will not trigger change detection
});

Thank you!

Learn zone.js by examples_shortver

By jiali

Learn zone.js by examples_shortver

  • 644