-
-
Notifications
You must be signed in to change notification settings - Fork 33.4k
diagnostics_channel: ensure tracePromise return values are unmodified #59944
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
diagnostics_channel: ensure tracePromise return values are unmodified #59944
Conversation
1820a73
to
031e853
Compare
Previously, the return value of tracePromise would depend on the presence or absence of subscribers.
031e853
to
bf941af
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #59944 +/- ##
==========================================
- Coverage 88.25% 88.24% -0.02%
==========================================
Files 703 703
Lines 207412 207416 +4
Branches 39893 39890 -3
==========================================
- Hits 183052 183031 -21
- Misses 16313 16354 +41
+ Partials 8047 8031 -16
🚀 New features to boost your workflow:
|
if (!isPromise(result) && typeof result?.then !== 'function') { | ||
context.result = result; | ||
} else { | ||
PromisePrototypeThen(PromiseResolve(result), resolve, reject); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doesn't this swallow a reject in case the caller never registers a than nor a catch handler?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does not. The returned promise isn't the one returned by .then()
, but the original promise, which remains rejected regardless of whether any reject callbacks have been called.
The promise returned by .then()
would indeed never reject, but this is just discarded.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did a fast try. Following test is green now but fails with your change:
'use strict';
const common = require('../common');
const dc = require('diagnostics_channel');
const assert = require('assert');
const channel = dc.tracingChannel('test');
const expectedError = new Error('test');
const input = { foo: 'bar' };
const thisArg = { baz: 'buz' };
process.on('unhandledRejection', common.mustCall((reason) => {
assert.deepStrictEqual(reason, expectedError);
}));
function check(found) {
assert.deepStrictEqual(found, input);
}
const handlers = {
start: common.mustCall(check),
end: common.mustCall(check),
asyncStart: common.mustCall(check),
asyncEnd: common.mustCall(check),
error: common.mustCall((found) => {
check(found);
assert.deepStrictEqual(found.error, expectedError);
})
};
channel.subscribe(handlers);
// Set no then/catch handler to verify unhandledRejection event
channel.tracePromise(function(value) {
assert.deepStrictEqual(this, thisArg);
return Promise.reject(value);
}, input, thisArg, expectedError);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unhandled rejection errors would indeed be suppressed by this approach.
@Renegade334 I'm not familiar with the rules of deciding where to land this but since this API is experimental would it really need to be in a semver major? |
For a significant change in return behaviour, this probably does still warrant a major change. I'll mock up a new approach later allowing returned chained thenables, as discussed in the associated issue. |
There are some behavioural issues with
tracingChannel.tracePromise()
:traceSync()
andtraceCallback()
pass their results through unchanged, whereastracePromise()
returns a newly constructed Promise. The original return value is never accessible to the user, which can cause issues if – say – the function originally returned a custom promise with additional methods/properties that the user needs to access.tracePromise()
currently behaves just liketraceSync()
, and passes through the function return value verbatim; whereas if any are registered, then it wraps and returns a new Promise. This is especially noticeable for non-promise return values:tracePromise(() => 42)
might return42
orPromise.resolve(42)
, depending on the state of the tracing channel.This change addresses these issues.
tracePromise()
now always returns the original function return value, and removes the unintentional state-dependent polymorphism.This does change the design of the API, so this is something of a request for comment. Would be a semver-majorPRs that contain breaking changes and should be released in the next major version.
change.
Fixes: #59936