• 跟踪异步操作

    跟踪异步操作

    我们已经看到了如何进入和退出 zones,现在让我们看看我们如何跟踪跨异步操作的 zones 。

    1. let rootZone = Zone.current;
    2. let zoneA = rootZone.fork({name: 'A'});
    3. expect(Zone.current).toBe(rootZone);
    4. // setTimeout调用时的zone是rootZone
    5. expect(Error.captureStackTrace()).toEqual(rootLocation)
    6. setTimeout(function timeoutCb1() {
    7. // 回调在rootZone中执行
    8. expect(Zone.current).toEqual(rootZone);
    9. expect(Error.captureStackTrace()).toEqual(rootLocationRestored)
    10. }, 0);
    11. zoneA.run(function run1() {
    12. expect(Zone.current).toEqual(zoneA);
    13. // setTimeout调用时的zone是zoneA
    14. expect(Error.captureStackTrace()).toEqual(zoneALocation)
    15. setTimeout(function timeoutCb2() {
    16. // 回调在zoneA中执行
    17. expect(Zone.current).toEqual(zoneA);
    18. expect(Error.captureStackTrace()).toEqual(zoneALocationRestored)
    19. }, 0);
    20. });
    1. rootLocation:
    2. at <anonymous>()[rootZone]
    3. rootLocationRestored:
    4. at timeoutCb1()[rootZone]
    5. at Zone.prototype.run()[<root> -> <root>]
    6. zoneALocation:
    7. at run1()[zoneA]
    8. at Zone.prototype.run()[<root> -> zoneA]
    9. at <anonymous>()[rootZone]
    10. zoneALocationRestored:
    11. at timeoutCb2()[zoneA]
    12. at Zone.prototype.run()[<root> -> zoneA]

    关键点:

    • 当调度异步工作时,回调函数将在与调用异步API时存在的相同 zone 中执行。 这允许跨越许多异步调用来跟踪 zone。

    类似示例使用promises。(Promises有点不同,因为它们在回调中处理自己的异常)

    1. let rootZone = Zone.current;
    2. // LibZone表示一些第三方库,开发人员无法控制。 这个zone仅用于说明目的。
    3. // 在实践中,大多数第三方库不可能有这种细粒度zone控制。
    4. let libZone = rootZone.fork({name: 'libZone'});
    5. // Represents a zone of an application which the developer does
    6. // control
    7. let appZone = rootZone.fork({name: 'appZone'});
    8. // In this Example we try to demonstrate the difference between
    9. // resolving a promise and listening to a promise. Promise
    10. // resolution could happen in a third party libZone.
    11. let promise = libZone.run(() => {
    12. return new Promise((resolve, reject) => {
    13. expect(Zone.current).toBe(libZone);
    14. // The Promise can be resolved immediately or at some later
    15. // point in time as in this example.
    16. setTimeout(() => {
    17. expect(Zone.current).toBe(libZone);
    18. // Promise is resolved in libZone, but this does not affect
    19. // the promise listeners.
    20. resolve('OK');
    21. }, 500);
    22. });
    23. });
    24. appZone.run(() => {
    25. promise.then(() => {
    26. // Because the developer controls the in which zone .then()
    27. // executes, they will expect that the callback will execute
    28. // the same zone, in this case the appZone.
    29. expect(Zone.current).toBe(appZone);
    30. });
    31. });

    关键点:

    • 对于Promise,在.then() 调用生效时 thenCallback 会在 zone 中被调用 。

      • 或者,我们可以为thenCallback使用不同的 zone ,例如Promise创建 zone 或Promise解析 zone 。 这两者都不是一个好的匹配,因为一个Promise可以在一个第三方库中创建和解析,它可以有自己的 zone 。 然后将所得到的承诺传递到在其自己的 zone 中运行的应用程序中。 如果应用程序在其自己的 zone 中注册.then(),那么它将期望它自己的 zone 传播。

        示例:调用fetch()返回一个promise。 内部fetch()可能使用自己的 zone 为自己的原因。 调用.then()的应用程序将期望应用程序 zone 。 (我们不希望fetch() zone 泄漏到我们的应用程序中。)