node.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /**
  2. * @license
  3. * Copyright Google Inc. All Rights Reserved.
  4. *
  5. * Use of this source code is governed by an MIT-style license that can be
  6. * found in the LICENSE file at https://angular.io/license
  7. */
  8. import './node_util';
  9. import './events';
  10. import './fs';
  11. import {findEventTasks} from '../common/events';
  12. import {patchTimer} from '../common/timers';
  13. import {ArraySlice, isMix, patchMacroTask, patchMicroTask} from '../common/utils';
  14. const set = 'set';
  15. const clear = 'clear';
  16. Zone.__load_patch('node_timers', (global: any, Zone: ZoneType) => {
  17. // Timers
  18. let globalUseTimeoutFromTimer = false;
  19. try {
  20. const timers = require('timers');
  21. let globalEqualTimersTimeout = global.setTimeout === timers.setTimeout;
  22. if (!globalEqualTimersTimeout && !isMix) {
  23. // 1. if isMix, then we are in mix environment such as Electron
  24. // we should only patch timers.setTimeout because global.setTimeout
  25. // have been patched
  26. // 2. if global.setTimeout not equal timers.setTimeout, check
  27. // whether global.setTimeout use timers.setTimeout or not
  28. const originSetTimeout = timers.setTimeout;
  29. timers.setTimeout = function() {
  30. globalUseTimeoutFromTimer = true;
  31. return originSetTimeout.apply(this, arguments);
  32. };
  33. const detectTimeout = global.setTimeout(() => {}, 100);
  34. clearTimeout(detectTimeout);
  35. timers.setTimeout = originSetTimeout;
  36. }
  37. patchTimer(timers, set, clear, 'Timeout');
  38. patchTimer(timers, set, clear, 'Interval');
  39. patchTimer(timers, set, clear, 'Immediate');
  40. } catch (error) {
  41. // timers module not exists, for example, when we using nativeScript
  42. // timers is not available
  43. }
  44. if (isMix) {
  45. // if we are in mix environment, such as Electron,
  46. // the global.setTimeout has already been patched,
  47. // so we just patch timers.setTimeout
  48. return;
  49. }
  50. if (!globalUseTimeoutFromTimer) {
  51. // 1. global setTimeout equals timers setTimeout
  52. // 2. or global don't use timers setTimeout(maybe some other library patch setTimeout)
  53. // 3. or load timers module error happens, we should patch global setTimeout
  54. patchTimer(global, set, clear, 'Timeout');
  55. patchTimer(global, set, clear, 'Interval');
  56. patchTimer(global, set, clear, 'Immediate');
  57. } else {
  58. // global use timers setTimeout, but not equals
  59. // this happens when use nodejs v0.10.x, global setTimeout will
  60. // use a lazy load version of timers setTimeout
  61. // we should not double patch timer's setTimeout
  62. // so we only store the __symbol__ for consistency
  63. global[Zone.__symbol__('setTimeout')] = global.setTimeout;
  64. global[Zone.__symbol__('setInterval')] = global.setInterval;
  65. global[Zone.__symbol__('setImmediate')] = global.setImmediate;
  66. }
  67. });
  68. // patch process related methods
  69. Zone.__load_patch('nextTick', () => {
  70. // patch nextTick as microTask
  71. patchMicroTask(process, 'nextTick', (self: any, args: any[]) => {
  72. return {
  73. name: 'process.nextTick',
  74. args: args,
  75. cbIdx: (args.length > 0 && typeof args[0] === 'function') ? 0 : -1,
  76. target: process
  77. };
  78. });
  79. });
  80. Zone.__load_patch(
  81. 'handleUnhandledPromiseRejection', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
  82. (Zone as any)[api.symbol('unhandledPromiseRejectionHandler')] =
  83. findProcessPromiseRejectionHandler('unhandledRejection');
  84. (Zone as any)[api.symbol('rejectionHandledHandler')] =
  85. findProcessPromiseRejectionHandler('rejectionHandled');
  86. // handle unhandled promise rejection
  87. function findProcessPromiseRejectionHandler(evtName: string) {
  88. return function(e: any) {
  89. const eventTasks = findEventTasks(process, evtName);
  90. eventTasks.forEach(eventTask => {
  91. // process has added unhandledrejection event listener
  92. // trigger the event listener
  93. if (evtName === 'unhandledRejection') {
  94. eventTask.invoke(e.rejection, e.promise);
  95. } else if (evtName === 'rejectionHandled') {
  96. eventTask.invoke(e.promise);
  97. }
  98. });
  99. };
  100. }
  101. });
  102. // Crypto
  103. Zone.__load_patch('crypto', () => {
  104. let crypto: any;
  105. try {
  106. crypto = require('crypto');
  107. } catch (err) {
  108. }
  109. // use the generic patchMacroTask to patch crypto
  110. if (crypto) {
  111. const methodNames = ['randomBytes', 'pbkdf2'];
  112. methodNames.forEach(name => {
  113. patchMacroTask(crypto, name, (self: any, args: any[]) => {
  114. return {
  115. name: 'crypto.' + name,
  116. args: args,
  117. cbIdx: (args.length > 0 && typeof args[args.length - 1] === 'function') ?
  118. args.length - 1 :
  119. -1,
  120. target: crypto
  121. };
  122. });
  123. });
  124. }
  125. });
  126. Zone.__load_patch('console', (global: any, Zone: ZoneType) => {
  127. const consoleMethods =
  128. ['dir', 'log', 'info', 'error', 'warn', 'assert', 'debug', 'timeEnd', 'trace'];
  129. consoleMethods.forEach((m: string) => {
  130. const originalMethod = (console as any)[Zone.__symbol__(m)] = (console as any)[m];
  131. if (originalMethod) {
  132. (console as any)[m] = function() {
  133. const args = ArraySlice.call(arguments);
  134. if (Zone.current === Zone.root) {
  135. return originalMethod.apply(this, args);
  136. } else {
  137. return Zone.root.run(originalMethod, this, args);
  138. }
  139. };
  140. }
  141. });
  142. });