diagnostics_channel: ensure tracePromise consistency with non-Promises

Merged
RE
7mo ago
+143-20

tracingChannel.tracePromise() is documented in the source code (albeit not in the docs) to accept functions that return non-Promise thenables. However, it currently has some wonky behaviour when the return value isn't a native Promise, and also in the undocumented case where the return value isn't promise-like at all.

What gets returned by tracePromise() is highly dependent on whether the tracing channel has active subscribers or not:

result type Without subscribers With subscribers
Return value Return type Return value Return type
Native Promise result Native Promise result.then(...) Native Promise
Custom thenable result Custom thenable Promise.resolve(result).then(...) Native Promise
Non-thenable result Non-thenable Promise.resolve(result).then(...) Native Promise

The major inconsistencies are:

  • If the wrapped function returns a custom thenable, then it will either be returned as a custom thenable or wrapped in a native Promise, depending on whether there are active subscribers.
  • If the wrapped function returns a non-thenable, then it will either be returned verbatim or wrapped in a resolved native Promise, depending on whether there are active subscribers.
  • In the case where the wrapped function synchronously returns a non-thenable, then tracePromise produces asyncStart/asyncEnd events, despite no asynchronous execution. On the other hand, if the wrapped function throws synchronously, these events are not produced.

This PR makes some changes to the non-Promise cases to make the behaviours consistent.

  • If the wrapped function returns either a Promise or a custom thenable, then the value returned by tracePromise will have the same type: either the original value (if no subscribers) or the value of result.then(...) (if active subscribers).
  • If the wrapped function returns a non-thenable result, then it is returned verbatim, and a warning is emitted. No asyncStart or asyncEnd events are produced.
result type Without subscribers With subscribers
Return value Return type Return value Return type
Native Promise result Native Promise result.then(...) Native Promise
Custom thenable result Custom thenable result.then(...) Custom thenable
Non-thenable result Non-thenable result Non-thenable

Fixes: #59936