Skip to content

Commit 1557841

Browse files
committed
2 batches of comments
1 parent 392d402 commit 1557841

File tree

6 files changed

+45
-31
lines changed

6 files changed

+45
-31
lines changed

doc/api/util.md

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,22 @@ callbackFunction((err, ret) => {
4141
});
4242
```
4343

44-
will print something like:
44+
Will print something like:
4545

4646
```txt
4747
hello world
4848
```
4949

5050
*Note*:
51+
5152
* Like with most callback style functions, the callback is executed in an
52-
async context (having a limited stacktrace), and if the callback throws the
53-
process will emit an `uncaughtException` event, and if not handled, will exit.
53+
async context (i.e. having a limited stacktrace). If the callback throws, the
54+
process will emit an `uncaughtException` event, and if not handled will exit.
55+
5456
* Since `null` has a special meaning as the first argument to a callback, if a
55-
wrapped function rejects a `Promise` with a "falsy" value as a reason, we wrap
56-
the value in an `Error` with that value stored in a field named `cause`.
57+
wrapped function rejects a `Promise` with a falsy value as a reason, the value
58+
is wrapped in an `Error` with the original value stored in a field named
59+
`reason`.
5760

5861
```js
5962
function fn() {
@@ -62,12 +65,12 @@ function fn() {
6265
const callbackFunction = util.callbackify(fn);
6366

6467
callbackFunction((err, ret) => {
65-
err && err.cause && err.cause === null; // true
66-
err && err.message === 'Error: null'; // true
68+
// When the Promise was rejected with `null` it is wrapped with an Error and
69+
// the original value is stored in `reason`.
70+
err && ('reason' in err) && err.reason === null; // true
6771
});
6872
```
6973

70-
7174
## util.debuglog(section)
7275
<!-- YAML
7376
added: v0.11.3

lib/internal/errors.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ E('ERR_SOCKET_BAD_PORT', 'Port should be > 0 and < 65536');
164164
E('ERR_SOCKET_DGRAM_NOT_RUNNING', 'Not running');
165165
E('ERR_V8BREAKITERATOR', 'full ICU data not installed. ' +
166166
'See https://github.com/nodejs/node/wiki/Intl');
167+
E('NULL_REJECTION', 'Promise was rejected with "null"');
167168
// Add new errors from here...
168169

169170
function invalidArgType(name, expected, actual) {

lib/util.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,9 +1052,10 @@ function callbackifyOnRejected(reason, cb) {
10521052
// occurred", we error-wrap so the callback consumer can distinguish between
10531053
// "the promise rejected with null" or "the promise fulfilled with undefined".
10541054
if (!reason) {
1055-
const newRej = new Error(String(reason));
1056-
newRej.cause = reason;
1057-
reason = newRej;
1055+
const newReason = new errors.Error('NULL_REJECTION');
1056+
newReason.reason = reason;
1057+
reason = newReason;
1058+
Error.captureStackTrace(reason, callbackifyOnRejected);
10581059
}
10591060
return cb(reason);
10601061
}

test/fixtures/uncaught-exceptions/callbackify1.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22

3-
// Used to test `uncaughtException` is emitted
3+
// Used to test that `uncaughtException` is emitted
44

55
const { callbackify } = require('util');
66

test/fixtures/uncaught-exceptions/callbackify2.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22

3-
// Used to test arguments to `uncaughtException` from a callback
3+
// Used to test the `uncaughtException` err object
44

55
const assert = require('assert');
66
const { callbackify } = require('util');

test/parallel/test-util-callbackify.js

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
'use strict';
22
const common = require('../common');
33

4+
// This test checks that the semantics of `util.callbackify` are as described in
5+
// the API docs
6+
47
const assert = require('assert');
58
const { callbackify } = require('util');
69
const { join } = require('path');
710
const { execFile } = require('child_process');
811
const fixtureDir = join(common.fixturesDir, 'uncaught-exceptions');
9-
const sentinalValues = [
12+
const sentinelValues = [
1013
'hello world',
1114
null,
1215
undefined,
@@ -18,8 +21,8 @@ const sentinalValues = [
1821
];
1922

2023
{
21-
// Just works
22-
for (const sentinel of sentinalValues) {
24+
// Test that the resolution value is passed as second argument to callback
25+
for (const sentinel of sentinelValues) {
2326
async function asyncFn() {
2427
return await Promise.resolve(sentinel);
2528
}
@@ -45,8 +48,8 @@ const sentinalValues = [
4548
}
4649

4750
{
48-
// Rejections
49-
for (const sentinel of sentinalValues) {
51+
// Test that rejection reason is passed as first argument to callback
52+
for (const sentinel of sentinelValues) {
5053
async function asyncFn() {
5154
return await Promise.reject(sentinel);
5255
}
@@ -56,16 +59,19 @@ const sentinalValues = [
5659
cbAsyncFn(common.mustCall((err, ret) => {
5760
assert.strictEqual(ret, undefined);
5861
if (err instanceof Error) {
59-
assert.strictEqual(String(sentinel).endsWith(err.message), true);
60-
if ('cause' in err)
61-
assert.strictEqual(err.cause, sentinel);
62+
if ('reason' in err) {
63+
assert.strictEqual(err.code, 'NULL_REJECTION');
64+
assert.strictEqual(err.reason, sentinel);
65+
} else {
66+
assert.strictEqual(String(sentinel).endsWith(err.message), true);
67+
}
6268
} else {
6369
assert.strictEqual(err, sentinel);
6470
}
6571
}));
6672
}
6773

68-
for (const sentinel of sentinalValues) {
74+
for (const sentinel of sentinelValues) {
6975
function promiseFn() {
7076
return Promise.reject(sentinel);
7177
}
@@ -75,9 +81,12 @@ const sentinalValues = [
7581
cbPromiseFn(common.mustCall((err, ret) => {
7682
assert.strictEqual(ret, undefined);
7783
if (err instanceof Error) {
78-
assert.strictEqual(String(sentinel).endsWith(err.message), true);
79-
if ('cause' in err)
80-
assert.strictEqual(err.cause, sentinel);
84+
if ('reason' in err) {
85+
assert.strictEqual(err.code, 'NULL_REJECTION');
86+
assert.strictEqual(err.reason, sentinel);
87+
} else {
88+
assert.strictEqual(String(sentinel).endsWith(err.message), true);
89+
}
8190
} else {
8291
assert.strictEqual(err, sentinel);
8392
}
@@ -86,8 +95,8 @@ const sentinalValues = [
8695
}
8796

8897
{
89-
// 3. args work
90-
for (const sentinel of sentinalValues) {
98+
// Test that arguments passed to callbackified function are passed to original
99+
for (const sentinel of sentinelValues) {
91100
async function asyncFn(arg) {
92101
assert.strictEqual(arg, sentinel);
93102
return await Promise.resolve(arg);
@@ -115,8 +124,8 @@ const sentinalValues = [
115124
}
116125

117126
{
118-
// `this` binding
119-
for (const sentinel of sentinalValues) {
127+
// Test that `this` binding is the same for callbackified and original
128+
for (const sentinel of sentinelValues) {
120129
const iAmThis = {
121130
fn(arg) {
122131
assert.strictEqual(this, iAmThis);
@@ -148,7 +157,7 @@ const sentinalValues = [
148157
}
149158

150159
{
151-
// `uncaughtException` aborts process
160+
// Test that callback that throws emits an `uncaughtException` event
152161
const fixture = join(fixtureDir, 'callbackify1.js');
153162
execFile(
154163
process.argv[0],
@@ -165,7 +174,7 @@ const sentinalValues = [
165174
}
166175

167176
{
168-
// handled `uncaughtException` works and passes rejection reason
177+
// Test that handled `uncaughtException` works and passes rejection reason
169178
const fixture = join(fixtureDir, 'callbackify2.js');
170179
execFile(
171180
process.argv[0],

0 commit comments

Comments
 (0)