Node Domains

postmortem
注意:

  • 文档得知:
    • 如果使用 domains,所有触发的事件对象(包括流对象,比如 request,response 等)都会在创建时隐式地与激活的 domain 绑定。
      • 我认为不应该这么做,更好的做法是在创建监听函数时绑定而不是在事件触发时绑定
  • Domains 在同步任务重的调用栈组合的很好,但是在异步任务中,只有最上层的 domains 会被存储。
    • 这一点与 zone 一致,但是 Domains 无法将其组合起来
    • 在讨论 zone 的时候,区分 zone 的调用栈和 zone 的构成是很重要的,看下面的例子
  1. let logs = [];
  2. let zoneA = Zone.current.fork({
  3. name: 'zoneA',
  4. onInvoke: function(delegate, currentZone, targetZone, callback, applyThis, applyArgs) {
  5. logs.push('zoneA onInvoke');
  6. return delegate.invoke(targetZone, callback, applyThis, applyArgs);
  7. }
  8. });
  9. let zoneB = Zone.current.fork({
  10. name: 'zoneB',
  11. onInvoke: function(delegate, currentZone, targetZone, callback, applyThis, applyArgs) {
  12. logs.push('zoneB onInvoke');
  13. return delegate.invoke(targetZone, callback, applyThis, applyArgs);
  14. }
  15. });
  16. let zoneAChild = zoneA.fork({
  17. name: 'zoneAChild',
  18. onInvoke: function(delegate, currentZone, targetZone, callback, applyThis, applyArgs) {
  19. logs.push('zoneAChild onInvoke');
  20. return delegate.invoke(targetZone, callback, applyThis, applyArgs);
  21. }
  22. });
  23. zoneA.run(() => {
  24. zoneB.run(() => {
  25. zoneAChild.run(function test() {
  26. logs.push('begin run' + Zone.current.name);
  27. console.log('logs', logs);
  28. const error = new Error();
  29. console.log('trace', error.stack);
  30. });
  31. });
  32. });

在这个例子中,

  1. zone 的调用栈是 -> zoneA -> zoneB -> zoneAChild,你可以在 error.stack 上找到这些 zone 的转移过程。
  2. zone 的组成是, zoneAChild -> zoneA -> rootZone,所以在这个例子中, zoneB 的回调不会被触发

    • 创建新的 zone 时,他是当前 zone 的子 zone ,而创建 domain 时,他是独立的。

      译注: 意思是你可以在调用栈中看到代码执行从 rootZone 转移到 zoneA 再到 zoneB 再到 zoneAChild,如果发生错误你可以很快找到原因。 但是实际执行时,代码其实是在最后交给的 zoneAChild 中执行的,因此只有 zoneAChild 的回调会被触发,而 zoneAChild 是 zoneA 的子 zone,因此 zoneA 的回调也会被触发,同理,rootZone 的回调也会被触发。