forked from angular/zone.js
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathnode_asynchooks.ts
91 lines (80 loc) · 2.92 KB
/
node_asynchooks.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* patch nodejs async operations (timer, promise, net...) with
* nodejs async_hooks
*/
Zone.__load_patch('node_async_hooks', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
let async_hooks;
const BEFORE_RUN_TASK_STATUS = 'BEFORE_RUN_TASK_STATUS';
async_hooks = require('async_hooks');
const idTaskMap: {[key: number]: Task} = (Zone as any)[Zone.__symbol__('nodeTasks')] = {};
const noop = function() {};
function init(id: number, provider: string, parentId: number, parentHandle: any) {
// @JiaLiPassion, check which tasks are microTask or macroTask
//(process as any)._rawDebug('init hook', id , provider);
if (provider === 'TIMERWRAP') {
return;
}
// create microTask if 'PROMISE'
if (provider === 'PROMISE') {
const task = idTaskMap[id] = Zone.current.scheduleMicroTask(provider, noop, null, noop);
//(process as any)._rawDebug('after init', id, 'status', task.state);
return;
}
// create macroTask in other cases
if (provider === 'Timeout' || provider === 'Immediate' || provider === 'FSREQWRAP') {
idTaskMap[id] = Zone.current.scheduleMacroTask(provider, noop, null, noop, noop);
}
}
function before(id: number) {
//(process as any)._rawDebug('before hook', id);
// call Zone.beforeRunTask
const task: Task = idTaskMap[id];
if (!task) {
return;
}
(task as any)[Zone.__symbol__(BEFORE_RUN_TASK_STATUS)] = api.beforeRunTask(task.zone, task);
}
function after(id: number) {
//(process as any)._rawDebug('after hook', id);
const task: Task = idTaskMap[id];
if (!task) {
return;
}
const beforeRunTask: BeforeRunTaskStatus = (task as any)[Zone.__symbol__(BEFORE_RUN_TASK_STATUS)];
if (beforeRunTask) {
return;
}
(task as any)[Zone.__symbol__(BEFORE_RUN_TASK_STATUS)] = null;
api.afterRunTask(task.zone, beforeRunTask, task);
}
function destroy(id: number) {
// try to cancel the task if is not canceled
const task: Task = idTaskMap[id];
if (task && task.state === 'scheduled') {
task.zone.cancelTask(task);
}
idTaskMap[id] = null;
}
process.on('uncaughtException', (err: any) => {
const task = Zone.currentTask;
if (task) {
const beforeRunTask: BeforeRunTaskStatus = (task as any)[Zone.__symbol__(BEFORE_RUN_TASK_STATUS)];
if (beforeRunTask) {
if ((task.zone as any)._zoneDelegate.handleError(Zone.current, err)) {
throw err;
}
}
}
});
global[Zone.__symbol__('setTimeout')] = global.setTimeout;
global[Zone.__symbol__('setInterval')] = global.setInterval;
global[Zone.__symbol__('setImmediate')] = global.setImmediate;
async_hooks.createHook({ init, before, after, destroy }).enable();
});