-
Notifications
You must be signed in to change notification settings - Fork 30k
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
util: add util.callbackify() #12712
util: add util.callbackify() #12712
Conversation
For how to treat the returned value I choose to:
P.S. treat this as pseudocode, since by the time my Windows machine finished compiling I'll be fast asleep, so I haven't verified it works :( |
/cc @chrisdickinson @benjamingr @Fishrock123 @nodejs/ctc |
I think option 1 is definitely best. The other options can easily be simulated in userland by using destructuring in the callback, so I don't think it's necessary to have special behavior to for spreading arrays/objects in core. |
lib/util.js
Outdated
throw new TypeError('The [util.callbackify.custom] property must be ' + | ||
'a function'); | ||
} | ||
Object.defineProperty(fn, kCustomCallbackifyiedSymbol, { |
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.
I'd protect this with if (fn[kCustomCallbackifyiedSymbol] !== fn)
as Object.defineProperty
may be quite slow.
lib/util.js
Outdated
} else if (project) { | ||
const allThere = project.all((k) => k in ret); | ||
if (!allThere) { | ||
throw new TypeError('Not all of the projected properties' + |
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.
I'd fill in undefined
for properties that are not present.
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.
I was wondering about that too.
Can we find some precedents? lodash
maybe?
lib/util.js
Outdated
|
||
callbackify.custom = kCustomCallbackifyiedSymbol; | ||
callbackify.toSplat = kCustomCallbackifyiedToSplat; | ||
callbackify.project = kCustomCallbackifyiedProject; |
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.
We should not make toSplat
or project
public for now, just like for promisify
.
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.
🤔 not sure, but keeping in line with promisify
lib/util.js
Outdated
@@ -1057,3 +1057,68 @@ exports._exceptionWithHostPort = function(err, | |||
// process.versions needs a custom function as some values are lazy-evaluated. | |||
process.versions[exports.inspect.custom] = | |||
(depth) => exports.format(JSON.parse(JSON.stringify(process.versions))); | |||
|
|||
const kCustomCallbackifyiedSymbol = Symbol('util.callbackify.custom'); |
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.
-kCustomCallbackifyiedSymbol
+kCustomCallbackifiedSymbol
?
This seems unnecessarily complicated for such a simple feature. Is there an example where you would need all that customization? |
lib/util.js
Outdated
} else if (project) { | ||
const allThere = project.all((k) => k in ret); | ||
if (!allThere) { | ||
throw new TypeError('Not all of the projected properties' + |
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.
If we keep this property-picking option, then I think this error should be sent with cb(new TypeError(...))
rather than throwing and rejecting the Promise. If someone is using callbackify
, then they're probably going to be listening for errors in the callback rather than listening for Promise rejections. (However, I don't think we should keep the property-picking option -- see #12712 (comment).)
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.
Yep. Didn't think of that.
lib/util.js
Outdated
} else { | ||
cb(null, ret); | ||
} | ||
}, cb); |
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.
This could cause confusing behavior if the original Promise rejects with a non-error:
function promiseFunction() {
return Promise.reject(null);
}
util.callbackify(promiseFunction)((err, result) => {
// err will be null, which could be confusing because the promise actually rejected.
});
Bluebird seems to handle this by wrapping the rejection reason in an Error
if it's falsy.
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.
Maybe even if !err instanceof Error
?
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.
I don't think that would be a good idea because people sometimes intentionally reject Promises with objects. If we wrapped the objects in errors then we would lose information about the properties.
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.
Adapted BlueBird snippet
lib/util.js
Outdated
} | ||
orig.call(this, ...args).then((ret) => { | ||
if (toSplat) { | ||
cb(null, ...ret); |
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.
What if cb
throws? We probably want to avoid getting rejected promises from callbackified functions
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.
What can we do? who can we tell?
Maybe process.emit('uncaughtException')
or 'unhandledRejection'?
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.
Maybe wrap the whole thing in process.nextTick
?
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.
So it'll go out of the Promise timeline?
I'd rather explicitly explode a la https://github.com/nodejs/node/pull/12712/files#diff-3deb3f32958bb937ae05c6f3e4abbdf5R1121
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.
Not a good idea, it's better to allow the error to bubble. Otherwise you'll have to duplicate a lot of logic here for no good reason.
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.
I'll check it out... (don't want to duplicate!)
Is there a use case for having |
🤔 I thought of it as an 'escape hatch' to allow users to do whatever. Maybe adapt to old I have in mind the use case where this is used by dev A to adapt dev B's and dev C's APIs into a new uniform API, and there is a need to tweak each adaptation a little. So I'm not even sure about hiding |
I think having customization here is unnecessary given that it's trivial for users to customize the behavior in userland. Adding extra configurability where it's not needed seems like it will make the API bloated. |
P.S. do you think we should return the Promise |
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.
Thanks for the work! awaiting changes.
lib/util.js
Outdated
|
||
const kCustomCallbackifiedSymbol = Symbol('util.callbackify.custom'); | ||
const kCustomCallbackifiedToSplat = Symbol('util.callbackify.toSplat'); | ||
const kCustomCallbackifiedProject = Symbol('util.callbackify.project'); |
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.
I don't think we need these properties - they complicate the PR and with destructuring syntax and a uniform convention none of the benefits it would bring to util.promisify
apply here IMO.
For example, it is required for fs.exists
to work in promisify
but there is no equivalent here.
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.
Came to same conclusion. Gone in last commit.
lib/util.js
Outdated
|
||
// we have two way to convert the returned value into multiple arguments | ||
// either splat it or project some of it's keys | ||
const toSplat = options.toSplat; |
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.
I don't think we should support this - with promisify
we don't really have a choice for things like fs.exists
but here destructuring syntax should be sufficient.
lib/util.js
Outdated
const toSplat = options.toSplat; | ||
const project = options.project; | ||
|
||
const fn = function(...args) { |
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.
Using ...args
args.pop
and call
with ...args
is expensive here.
I would prefer to see arguments
used, apply
instead of call, and an inline slice instead of .pop
for performance like bluebird does.
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.
Since this will probably go on top of TF+I, is this still a major issue?
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.
Just noting to keep it in mind, it's not yet clear when we'll be enabling TF+I. It's entirely possible that this could land before that but hard to say for sure.
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.
I'll cook up some benchmarks (also look for DEOPTS)...
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.
If you run this on top of TF+I (by checking out the appropriate branch) and the results show that these optimizations are meaningless - then we can drop them. I suspect they still affect execution speed on TF+I.
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.
@benjamingr Fwiw, there have been PRs like #12183 opened by V8 people. I’m good with using rest parameters here, at least for this PR.
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.
Interesting, @hashseed care to weigh in?
lib/util.js
Outdated
} | ||
var p = orig.call(this, ...args); | ||
if (typeof options.transformer === 'function') { | ||
p = options.transformer(p); |
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.
similar comment about not needing a transformer.
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.
Rest parameters are at least as fast as arguments object, and avoids many performance cliffs. Spread is just as fast as Function.prototype.apply
. If I remember correctly this applies to both Crankshaft and Turbofan.
@psmarshall and @bmeurer have more details though.
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.
In any case, the runtime of this function is likely to be dominated by the chaining of the promise that follows. I wouldn't micro-optimize this just yet, and opt for the cleaner syntax.
lib/util.js
Outdated
p = options.transformer(p); | ||
} | ||
p = p.then((ret) => { | ||
if (toSplat) { |
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.
You have to call cb
inside a process.nextTick
in case it throws - you can't just abort the process or emit an event since it has to work with domains.
This is what bluebird and other libraries do with their implementations and it's the most reasonable thing to do.
I would also avoid all the if/else
here and the projection - which users can just do in a second then
.
lib/util.js
Outdated
cb(null, ret); | ||
} | ||
}, (rej) => { | ||
// !rej guard inspired by BlueBird https://goo.gl/t5IS6M |
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.
At bluebird, this improves debugging experience. In Node this is not something we can afford - converting non-errors into errors is useful for a library but it's not something the platform should do.
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.
Ref: #12712 (comment)
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.
I saw that, but we can't assume that if someone threw a falsey value it should be converted to an error. Bluebird does this to overcome the lack of stack trace but node should not make that decision for users. As a platform we should provide a more careful API.
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.
To clarify, I didn't suggest doing this so that errors would have a stack trace -- I suggested it because null
is a special error value in callbacks which means "no error occurred". If we don't error-wrap, there is no way for a callback consumer to distinguish between "the promise rejected with null
" and "the promise fulfilled with undefined
".
lib/util.js
Outdated
rej = newRej; | ||
} | ||
cb(rej); | ||
}).catch((e) => process.emit('uncaughtException', e)); |
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.
Ditto, this catch is incorrect, and the error must be emitted in nextTick
, otherwise this breaks post-mortem debugging.
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.
I'm looking into this (and the nextTick
)
Ref: #12712 (comment)
P.S. .catch
happens on nextTick
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.
@refack the problem isn't that catch happens on nextTick
, it's that if you abort on unhandled exception the error would be thrown properly and the heap would not be possibly corrupted.
(Also, catch
happens after nextTick, not during)
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.
So you want an "explosion", callback throwing style? Makes sense.
Last commit goes full-on with the options. |
lib/util.js
Outdated
} | ||
cb(rej); | ||
}).catch((e) => process.emit('uncaughtException', e)); | ||
return p; |
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.
Should we return the promise?
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.
No, we should return undefined
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.
Reason?
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 gives the user a false sense that the promise is actually somehow related to the callback's execution and creates a confusing API in which the user might expect the callback throwing to reject the promise.
This is why we switched from returning the promise to returning undefined
in bluebird.
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.
I'm going to document that
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.
Basically, people were doing things like the following with BB:
await promise.asCallback((err, data) => {
console.log("2");
});
console.log("1");
And expected 2, 1 to log (and got 1,2), not to mention people thinking that if they nest callbacks it will somehow magically wait for them.
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.
Documented.
But added an option to opt-in to such behaviour 😉
I don't think this is necessary either, for the same reasons as #12712 (comment). I think we should just remove these options and the related functionality. |
No docs.... no comment (how could I if I don't know what its supposed to do?). No node API returns promises, does it? What is the API for? (see above.... "no docs"). |
lib/util.js
Outdated
const cb = args.pop(); | ||
if (typeof cb !== 'function') { | ||
throw new TypeError('The first argument to the callbackified function ' + | ||
'must be a callback style function'); |
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.
last argument
?
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.
Fixed.
lib/util.js
Outdated
p = options.transformer(p); | ||
} | ||
p = p.then((ret) => process.nextTick(onFulfilled, {ret, options, cb}), | ||
(rej) => process.nextTick(onRejected, {rej, cb})); |
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.
Is there any reason for creating objects here? Just passing them as 2 or 3 extra arguments to nextTick
should be fine
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.
I had something else in mind, but now you're obviously right. Fixed.
(p.then((ret) =>{ret, options, cb}).then(onFulfilled)
)
While the |
With latest comments incorporated IMHO two
|
@refack I think both of these still complicate the PR beyond scope, and may be added later if we really want them for some reason. |
Add `util.callbackify(function)` for creating callback style functions from functions returning a `Thenable` PR-URL: nodejs#12712 Fixes: nodejs/CTC#109 Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Teddy Katz <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Timothy Gu <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
The `FALSY_VALUE_REJECTION` error code added by nodejs#12712 did not have the `ERR_` prefix, nor was it added to the errors.md documentation. Add the prefix in for consistency. PR-URL: nodejs#13604 Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: Timothy Gu <[email protected]> Reviewed-By: Gibson Fahnestock <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Refael Ackermann <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]>
Add `util.callbackify(function)` for creating callback style functions from functions returning a `Thenable` Original-PR-URL: #12712 Fixes: nodejs/CTC#109 Original-Reviewed-By: Benjamin Gruenbaum <[email protected]> Original-Reviewed-By: Teddy Katz <[email protected]> Original-Reviewed-By: Matteo Collina <[email protected]> Original-Reviewed-By: Colin Ihrig <[email protected]> Original-Reviewed-By: Timothy Gu <[email protected]> Original-Reviewed-By: Anna Henningsen <[email protected]> PR-URL: #13750 Reviewed-By: Anna Henningsen <[email protected]>
The `FALSY_VALUE_REJECTION` error code added by #12712 did not have the `ERR_` prefix, nor was it added to the errors.md documentation. Add the prefix in for consistency. Original-PR-URL: #13604 Original-Reviewed-By: Luigi Pinca <[email protected]> Original-Reviewed-By: Timothy Gu <[email protected]> Original-Reviewed-By: Gibson Fahnestock <[email protected]> Original-Reviewed-By: Anna Henningsen <[email protected]> Original-Reviewed-By: Refael Ackermann <[email protected]> Original-Reviewed-By: Colin Ihrig <[email protected]> Original-Reviewed-By: Benjamin Gruenbaum <[email protected]> PR-URL: #13750 Reviewed-By: Anna Henningsen <[email protected]>
Add `util.callbackify(function)` for creating callback style functions from functions returning a `Thenable` Original-PR-URL: #12712 Fixes: nodejs/CTC#109 Original-Reviewed-By: Benjamin Gruenbaum <[email protected]> Original-Reviewed-By: Teddy Katz <[email protected]> Original-Reviewed-By: Matteo Collina <[email protected]> Original-Reviewed-By: Colin Ihrig <[email protected]> Original-Reviewed-By: Timothy Gu <[email protected]> Original-Reviewed-By: Anna Henningsen <[email protected]> PR-URL: #13750 Reviewed-By: Anna Henningsen <[email protected]>
The `FALSY_VALUE_REJECTION` error code added by #12712 did not have the `ERR_` prefix, nor was it added to the errors.md documentation. Add the prefix in for consistency. Original-PR-URL: #13604 Original-Reviewed-By: Luigi Pinca <[email protected]> Original-Reviewed-By: Timothy Gu <[email protected]> Original-Reviewed-By: Gibson Fahnestock <[email protected]> Original-Reviewed-By: Anna Henningsen <[email protected]> Original-Reviewed-By: Refael Ackermann <[email protected]> Original-Reviewed-By: Colin Ihrig <[email protected]> Original-Reviewed-By: Benjamin Gruenbaum <[email protected]> PR-URL: #13750 Reviewed-By: Anna Henningsen <[email protected]>
Add `util.callbackify(function)` for creating callback style functions from functions returning a `Thenable` Original-PR-URL: #12712 Fixes: nodejs/CTC#109 Original-Reviewed-By: Benjamin Gruenbaum <[email protected]> Original-Reviewed-By: Teddy Katz <[email protected]> Original-Reviewed-By: Matteo Collina <[email protected]> Original-Reviewed-By: Colin Ihrig <[email protected]> Original-Reviewed-By: Timothy Gu <[email protected]> Original-Reviewed-By: Anna Henningsen <[email protected]> PR-URL: #13750 Reviewed-By: Anna Henningsen <[email protected]>
The `FALSY_VALUE_REJECTION` error code added by #12712 did not have the `ERR_` prefix, nor was it added to the errors.md documentation. Add the prefix in for consistency. Original-PR-URL: #13604 Original-Reviewed-By: Luigi Pinca <[email protected]> Original-Reviewed-By: Timothy Gu <[email protected]> Original-Reviewed-By: Gibson Fahnestock <[email protected]> Original-Reviewed-By: Anna Henningsen <[email protected]> Original-Reviewed-By: Refael Ackermann <[email protected]> Original-Reviewed-By: Colin Ihrig <[email protected]> Original-Reviewed-By: Benjamin Gruenbaum <[email protected]> PR-URL: #13750 Reviewed-By: Anna Henningsen <[email protected]>
Add `util.callbackify(function)` for creating callback style functions from functions returning a `Thenable` Original-PR-URL: #12712 Fixes: nodejs/CTC#109 Original-Reviewed-By: Benjamin Gruenbaum <[email protected]> Original-Reviewed-By: Teddy Katz <[email protected]> Original-Reviewed-By: Matteo Collina <[email protected]> Original-Reviewed-By: Colin Ihrig <[email protected]> Original-Reviewed-By: Timothy Gu <[email protected]> Original-Reviewed-By: Anna Henningsen <[email protected]> PR-URL: #13750 Reviewed-By: Anna Henningsen <[email protected]>
The `FALSY_VALUE_REJECTION` error code added by #12712 did not have the `ERR_` prefix, nor was it added to the errors.md documentation. Add the prefix in for consistency. Original-PR-URL: #13604 Original-Reviewed-By: Luigi Pinca <[email protected]> Original-Reviewed-By: Timothy Gu <[email protected]> Original-Reviewed-By: Gibson Fahnestock <[email protected]> Original-Reviewed-By: Anna Henningsen <[email protected]> Original-Reviewed-By: Refael Ackermann <[email protected]> Original-Reviewed-By: Colin Ihrig <[email protected]> Original-Reviewed-By: Benjamin Gruenbaum <[email protected]> PR-URL: #13750 Reviewed-By: Anna Henningsen <[email protected]>
Add `util.callbackify(function)` for creating callback style functions from functions returning a `Thenable` Original-PR-URL: #12712 Fixes: nodejs/CTC#109 Original-Reviewed-By: Benjamin Gruenbaum <[email protected]> Original-Reviewed-By: Teddy Katz <[email protected]> Original-Reviewed-By: Matteo Collina <[email protected]> Original-Reviewed-By: Colin Ihrig <[email protected]> Original-Reviewed-By: Timothy Gu <[email protected]> Original-Reviewed-By: Anna Henningsen <[email protected]> PR-URL: #13750 Reviewed-By: Anna Henningsen <[email protected]>
The `FALSY_VALUE_REJECTION` error code added by #12712 did not have the `ERR_` prefix, nor was it added to the errors.md documentation. Add the prefix in for consistency. Original-PR-URL: #13604 Original-Reviewed-By: Luigi Pinca <[email protected]> Original-Reviewed-By: Timothy Gu <[email protected]> Original-Reviewed-By: Gibson Fahnestock <[email protected]> Original-Reviewed-By: Anna Henningsen <[email protected]> Original-Reviewed-By: Refael Ackermann <[email protected]> Original-Reviewed-By: Colin Ihrig <[email protected]> Original-Reviewed-By: Benjamin Gruenbaum <[email protected]> PR-URL: #13750 Reviewed-By: Anna Henningsen <[email protected]>
Add `util.callbackify(function)` for creating callback style functions from functions returning a `Thenable` Original-PR-URL: #12712 Fixes: nodejs/CTC#109 Original-Reviewed-By: Benjamin Gruenbaum <[email protected]> Original-Reviewed-By: Teddy Katz <[email protected]> Original-Reviewed-By: Matteo Collina <[email protected]> Original-Reviewed-By: Colin Ihrig <[email protected]> Original-Reviewed-By: Timothy Gu <[email protected]> Original-Reviewed-By: Anna Henningsen <[email protected]> PR-URL: #13750 Reviewed-By: Anna Henningsen <[email protected]>
The `FALSY_VALUE_REJECTION` error code added by #12712 did not have the `ERR_` prefix, nor was it added to the errors.md documentation. Add the prefix in for consistency. Original-PR-URL: #13604 Original-Reviewed-By: Luigi Pinca <[email protected]> Original-Reviewed-By: Timothy Gu <[email protected]> Original-Reviewed-By: Gibson Fahnestock <[email protected]> Original-Reviewed-By: Anna Henningsen <[email protected]> Original-Reviewed-By: Refael Ackermann <[email protected]> Original-Reviewed-By: Colin Ihrig <[email protected]> Original-Reviewed-By: Benjamin Gruenbaum <[email protected]> PR-URL: #13750 Reviewed-By: Anna Henningsen <[email protected]>
This is a first draft of an implementation of
util.callbackify(function)
.There is at least one issue that need ironing out: if and how to project the return value into multiple args...
Implementation inspired by @addaleax's #12442
Background discussion at: nodejs/CTC#109
Open discussion
Should we allow customization of the wrapping?
awaitable
before the connection to the callbackOriginal commit descriptions
Add
util.callbackify(function)
for creating callback style functionsfrom functions returning a
Promise
/awaitable
Fixes: nodejs/CTC#109
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
util