process: add --unhandled-rejections flag · nodejs/node@9dcc9b6 (original) (raw)
1
1
`'use strict';
`
2
2
``
3
``
`-
const { safeToString } = internalBinding('util');
`
``
3
`+
const { Object } = primordials;
`
``
4
+
``
5
`+
const {
`
``
6
`+
safeToString
`
``
7
`+
} = internalBinding('util');
`
4
8
`const {
`
5
9
` tickInfo,
`
6
10
`promiseRejectEvents: {
`
`@@ -9,7 +13,8 @@ const {
`
9
13
` kPromiseResolveAfterResolved,
`
10
14
` kPromiseRejectAfterResolved
`
11
15
`},
`
12
``
`-
setPromiseRejectCallback
`
``
16
`+
setPromiseRejectCallback,
`
``
17
`+
triggerFatalException
`
13
18
`} = internalBinding('task_queue');
`
14
19
``
15
20
`// Must match Environment::TickInfo::Fields in src/env.h.
`
`@@ -20,6 +25,15 @@ const pendingUnhandledRejections = [];
`
20
25
`const asyncHandledRejections = [];
`
21
26
`let lastPromiseId = 0;
`
22
27
``
``
28
`+
const states = {
`
``
29
`+
none: 0,
`
``
30
`+
warn: 1,
`
``
31
`+
strict: 2,
`
``
32
`+
default: 3
`
``
33
`+
};
`
``
34
+
``
35
`+
let state;
`
``
36
+
23
37
`function setHasRejectionToWarn(value) {
`
24
38
`tickInfo[kHasRejectionToWarn] = value ? 1 : 0;
`
25
39
`}
`
`@@ -29,6 +43,10 @@ function hasRejectionToWarn() {
`
29
43
`}
`
30
44
``
31
45
`function promiseRejectHandler(type, promise, reason) {
`
``
46
`+
if (state === undefined) {
`
``
47
`+
const { getOptionValue } = require('internal/options');
`
``
48
`+
state = states[getOptionValue('--unhandled-rejections') || 'default'];
`
``
49
`+
}
`
32
50
`switch (type) {
`
33
51
`case kPromiseRejectWithNoHandler:
`
34
52
`unhandledRejection(promise, reason);
`
`@@ -59,6 +77,7 @@ function unhandledRejection(promise, reason) {
`
59
77
`uid: ++lastPromiseId,
`
60
78
`warned: false
`
61
79
`});
`
``
80
`+
// This causes the promise to be referenced at least for one tick.
`
62
81
`pendingUnhandledRejections.push(promise);
`
63
82
`setHasRejectionToWarn(true);
`
64
83
`}
`
`@@ -85,14 +104,16 @@ function handledRejection(promise) {
`
85
104
``
86
105
`const unhandledRejectionErrName = 'UnhandledPromiseRejectionWarning';
`
87
106
`function emitWarning(uid, reason) {
`
88
``
`-
// eslint-disable-next-line no-restricted-syntax
`
89
``
`-
const warning = new Error(
`
``
107
`+
if (state === states.none) {
`
``
108
`+
return;
`
``
109
`+
}
`
``
110
`+
const warning = getError(
`
``
111
`+
unhandledRejectionErrName,
`
90
112
`'Unhandled promise rejection. This error originated either by ' +
`
91
``
`-
'throwing inside of an async function without a catch block, ' +
`
92
``
`-
'or by rejecting a promise which was not handled with .catch(). ' +
`
93
``
`` -
(rejection id: ${uid})
``
``
113
`+
'throwing inside of an async function without a catch block, ' +
`
``
114
`+
'or by rejecting a promise which was not handled with .catch(). ' +
`
``
115
`` +
(rejection id: ${uid})
``
94
116
`);
`
95
``
`-
warning.name = unhandledRejectionErrName;
`
96
117
`try {
`
97
118
`if (reason instanceof Error) {
`
98
119
`warning.stack = reason.stack;
`
`@@ -108,7 +129,7 @@ function emitWarning(uid, reason) {
`
108
129
``
109
130
`let deprecationWarned = false;
`
110
131
`function emitDeprecationWarning() {
`
111
``
`-
if (!deprecationWarned) {
`
``
132
`+
if (state === states.default && !deprecationWarned) {
`
112
133
`deprecationWarned = true;
`
113
134
`process.emitWarning(
`
114
135
`'Unhandled promise rejections are deprecated. In the future, ' +
`
`@@ -133,18 +154,57 @@ function processPromiseRejections() {
`
133
154
`while (len--) {
`
134
155
`const promise = pendingUnhandledRejections.shift();
`
135
156
`const promiseInfo = maybeUnhandledPromises.get(promise);
`
136
``
`-
if (promiseInfo !== undefined) {
`
137
``
`-
promiseInfo.warned = true;
`
138
``
`-
const { reason, uid } = promiseInfo;
`
139
``
`-
if (!process.emit('unhandledRejection', reason, promise)) {
`
140
``
`-
emitWarning(uid, reason);
`
141
``
`-
}
`
142
``
`-
maybeScheduledTicks = true;
`
``
157
`+
if (promiseInfo === undefined) {
`
``
158
`+
continue;
`
``
159
`+
}
`
``
160
`+
promiseInfo.warned = true;
`
``
161
`+
const { reason, uid } = promiseInfo;
`
``
162
`+
if (state === states.strict) {
`
``
163
`+
fatalException(reason);
`
143
164
`}
`
``
165
`+
if (!process.emit('unhandledRejection', reason, promise) ||
`
``
166
`+
// Always warn in case the user requested it.
`
``
167
`+
state === states.warn) {
`
``
168
`+
emitWarning(uid, reason);
`
``
169
`+
}
`
``
170
`+
maybeScheduledTicks = true;
`
144
171
`}
`
145
172
`return maybeScheduledTicks || pendingUnhandledRejections.length !== 0;
`
146
173
`}
`
147
174
``
``
175
`+
function getError(name, message) {
`
``
176
`+
// Reset the stack to prevent any overhead.
`
``
177
`+
const tmp = Error.stackTraceLimit;
`
``
178
`+
Error.stackTraceLimit = 0;
`
``
179
`+
// eslint-disable-next-line no-restricted-syntax
`
``
180
`+
const err = new Error(message);
`
``
181
`+
Error.stackTraceLimit = tmp;
`
``
182
`+
Object.defineProperty(err, 'name', {
`
``
183
`+
value: name,
`
``
184
`+
enumerable: false,
`
``
185
`+
writable: true,
`
``
186
`+
configurable: true,
`
``
187
`+
});
`
``
188
`+
return err;
`
``
189
`+
}
`
``
190
+
``
191
`+
function fatalException(reason) {
`
``
192
`+
let err;
`
``
193
`+
if (reason instanceof Error) {
`
``
194
`+
err = reason;
`
``
195
`+
} else {
`
``
196
`+
err = getError(
`
``
197
`+
'UnhandledPromiseRejection',
`
``
198
`+
'This error originated either by ' +
`
``
199
`+
'throwing inside of an async function without a catch block, ' +
`
``
200
`+
'or by rejecting a promise which was not handled with .catch().' +
`
``
201
`` +
The promise rejected with the reason "${safeToString(reason)}".
``
``
202
`+
);
`
``
203
`+
err.code = 'ERR_UNHANDLED_REJECTION';
`
``
204
`+
}
`
``
205
`+
triggerFatalException(err, true /* fromPromise */);
`
``
206
`+
}
`
``
207
+
148
208
`function listenForRejections() {
`
149
209
`setPromiseRejectCallback(promiseRejectHandler);
`
150
210
`}
`