Skip to content
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

Merged
merged 1 commit into from
Jun 11, 2017
Merged

util: add util.callbackify() #12712

merged 1 commit into from
Jun 11, 2017

Conversation

refack
Copy link
Contributor

@refack refack commented Apr 28, 2017

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?

  1. specifying a transform for the awaitable before the connection to the callback
  2. projection of the returned value
  3. tiying in the callback into the promise's life-cycle

Original commit descriptions

Add util.callbackify(function) for creating callback style functions

from functions returning a Promise/awaitable

Fixes: nodejs/CTC#109

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines
Affected core subsystem(s)

util

@refack refack added wip Issues and PRs that are still a work in progress. notable-change PRs with changes that should be highlighted in changelogs. util Issues and PRs related to the built-in util module. labels Apr 28, 2017
@refack refack self-assigned this Apr 28, 2017
@nodejs-github-bot nodejs-github-bot added the util Issues and PRs related to the built-in util module. label Apr 28, 2017
@refack
Copy link
Contributor Author

refack commented Apr 28, 2017

For how to treat the returned value I choose to:

  1. By default pass on as-is
  2. Allow the user to ask us to splat the value
  3. Allow the user to specify a list of keys that we will project out of the value
  4. [Just thought of] allow the user to provide a projection lambda

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 :(

@refack
Copy link
Contributor Author

refack commented Apr 28, 2017

/cc @chrisdickinson @benjamingr @Fishrock123 @nodejs/ctc

@refack refack requested a review from addaleax April 28, 2017 02:30
@not-an-aardvark
Copy link
Contributor

For how to treat the returned value I choose to:

  1. By default pass on as-is
  2. Allow the user to ask us to splat the value
  3. Allow the user to specify a list of keys that we will project out of the value
  4. [Just thought of] allow the user to provide a projection lambda

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, {
Copy link
Member

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' +
Copy link
Member

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.

Copy link
Contributor Author

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;
Copy link
Member

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.

Copy link
Contributor Author

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');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-kCustomCallbackifyiedSymbol
+kCustomCallbackifiedSymbol 

?

@vkurchatkin
Copy link
Contributor

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' +
Copy link
Contributor

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).)

Copy link
Contributor Author

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);
Copy link
Contributor

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.

Copy link
Contributor Author

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?

Copy link
Contributor

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.

Copy link
Contributor Author

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);
Copy link
Contributor

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

Copy link
Contributor Author

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'?

Copy link
Contributor

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?

Copy link
Contributor Author

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

Copy link
Contributor

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.

Copy link
Contributor Author

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!)

@not-an-aardvark
Copy link
Contributor

Is there a use case for having util.callbackify.custom? util.promisify.custom is useful because some functions have different callback conventions and so the default implementation wouldn't work, but that isn't the case with util.callbackify because all promise-returning functions just return a promise without separate conventions.

@refack
Copy link
Contributor Author

refack commented Apr 28, 2017

Is there a use case for having util.callbackify.custom?

🤔 I thought of it as an 'escape hatch' to allow users to do whatever. Maybe adapt to old Promise implementations like our mpromise that doesn't have a catch

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 callbackify.toSplat && callbackify.project. I think it makes the implementation more complete...

@not-an-aardvark
Copy link
Contributor

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.

@refack
Copy link
Contributor Author

refack commented Apr 28, 2017

P.S. do you think we should return the Promise
return orig.call(this, ...args).then((ret) => {
https://github.com/nodejs/node/pull/12712/files#diff-3deb3f32958bb937ae05c6f3e4abbdf5R1096
So the user could add a .catch or chain something?

Copy link
Member

@benjamingr benjamingr left a 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');
Copy link
Member

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.

Copy link
Contributor Author

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;
Copy link
Member

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) {
Copy link
Member

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.

Copy link
Contributor Author

@refack refack Apr 28, 2017

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?

Copy link
Member

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.

Copy link
Contributor Author

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)...

Copy link
Member

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.

Copy link
Member

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.

Copy link
Member

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);
Copy link
Member

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.

Copy link
Member

@hashseed hashseed Apr 29, 2017

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.

Copy link
Member

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) {
Copy link
Member

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
Copy link
Member

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

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.

Copy link
Contributor

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));
Copy link
Member

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.

Copy link
Contributor Author

@refack refack Apr 28, 2017

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

Copy link
Member

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)

Copy link
Contributor Author

@refack refack Apr 28, 2017

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.

@refack
Copy link
Contributor Author

refack commented Apr 28, 2017

Last commit goes full-on with the options.
For your consideration...

lib/util.js Outdated
}
cb(rej);
}).catch((e) => process.emit('uncaughtException', e));
return p;
Copy link
Contributor Author

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?

Copy link
Member

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reason?

Copy link
Member

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.

Copy link
Contributor Author

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

Copy link
Member

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.

Copy link
Contributor Author

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 😉

@not-an-aardvark
Copy link
Contributor

Last commit goes full-on with the options.
For your consideration...

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.

@sam-github
Copy link
Contributor

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');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

last argument?

Copy link
Contributor Author

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}));
Copy link
Member

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

Copy link
Contributor Author

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))

@addaleax addaleax added the semver-minor PRs that contain new features and should be released in the next minor version. label Apr 28, 2017
@Fishrock123 Fishrock123 self-assigned this Apr 28, 2017
@refack
Copy link
Contributor Author

refack commented Apr 29, 2017

While the options is still in debate, I added option.catch allowing the user to tie-in the callback to the underlying promise's life cycles and, hance also returning the promise in this case.

@refack
Copy link
Contributor Author

refack commented Apr 29, 2017

With latest comments incorporated IMHO two options have a meaningful use case

  1. project - when the expected consumer is a user of a mixed API and expects uniform callback signatures (where the wrapped awaitable is a part of an API made by 3rd party)
  2. catch - opt-in to incorporate the callback into the lifecycle of the underlying awaitable, i.e. having
    await util.callbackify(RunAsync, {catch: ture})((err, data) => {
       console.log("1");
    });
    console.log("2");
    print 1, 2

@benjamingr
Copy link
Member

@refack catch should be on my default (otherwise what, no errors?) and project can just be something you call on the function later.

I think both of these still complicate the PR beyond scope, and may be added later if we really want them for some reason.

@addaleax
Copy link
Member

@refack Can you backport (together with 873e2f2)?

refack added a commit to refack/node that referenced this pull request Jun 17, 2017
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 <benjamingr@gmail.com>
Reviewed-By: Teddy Katz <teddy.katz@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Timothy Gu <timothygu99@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
refack pushed a commit to refack/node that referenced this pull request Jun 17, 2017
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 <luigipinca@gmail.com>
Reviewed-By: Timothy Gu <timothygu99@gmail.com>
Reviewed-By: Gibson Fahnestock <gibfahn@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
addaleax pushed a commit that referenced this pull request Jun 20, 2017
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 <benjamingr@gmail.com>
Original-Reviewed-By: Teddy Katz <teddy.katz@gmail.com>
Original-Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Original-Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Original-Reviewed-By: Timothy Gu <timothygu99@gmail.com>
Original-Reviewed-By: Anna Henningsen <anna@addaleax.net>

PR-URL: #13750
Reviewed-By: Anna Henningsen <anna@addaleax.net>
addaleax pushed a commit that referenced this pull request Jun 20, 2017
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 <luigipinca@gmail.com>
Original-Reviewed-By: Timothy Gu <timothygu99@gmail.com>
Original-Reviewed-By: Gibson Fahnestock <gibfahn@gmail.com>
Original-Reviewed-By: Anna Henningsen <anna@addaleax.net>
Original-Reviewed-By: Refael Ackermann <refack@gmail.com>
Original-Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Original-Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>

PR-URL: #13750
Reviewed-By: Anna Henningsen <anna@addaleax.net>
addaleax pushed a commit that referenced this pull request Jun 21, 2017
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 <benjamingr@gmail.com>
Original-Reviewed-By: Teddy Katz <teddy.katz@gmail.com>
Original-Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Original-Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Original-Reviewed-By: Timothy Gu <timothygu99@gmail.com>
Original-Reviewed-By: Anna Henningsen <anna@addaleax.net>

PR-URL: #13750
Reviewed-By: Anna Henningsen <anna@addaleax.net>
addaleax pushed a commit that referenced this pull request Jun 21, 2017
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 <luigipinca@gmail.com>
Original-Reviewed-By: Timothy Gu <timothygu99@gmail.com>
Original-Reviewed-By: Gibson Fahnestock <gibfahn@gmail.com>
Original-Reviewed-By: Anna Henningsen <anna@addaleax.net>
Original-Reviewed-By: Refael Ackermann <refack@gmail.com>
Original-Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Original-Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>

PR-URL: #13750
Reviewed-By: Anna Henningsen <anna@addaleax.net>
addaleax pushed a commit that referenced this pull request Jun 24, 2017
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 <benjamingr@gmail.com>
Original-Reviewed-By: Teddy Katz <teddy.katz@gmail.com>
Original-Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Original-Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Original-Reviewed-By: Timothy Gu <timothygu99@gmail.com>
Original-Reviewed-By: Anna Henningsen <anna@addaleax.net>

PR-URL: #13750
Reviewed-By: Anna Henningsen <anna@addaleax.net>
addaleax pushed a commit that referenced this pull request Jun 24, 2017
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 <luigipinca@gmail.com>
Original-Reviewed-By: Timothy Gu <timothygu99@gmail.com>
Original-Reviewed-By: Gibson Fahnestock <gibfahn@gmail.com>
Original-Reviewed-By: Anna Henningsen <anna@addaleax.net>
Original-Reviewed-By: Refael Ackermann <refack@gmail.com>
Original-Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Original-Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>

PR-URL: #13750
Reviewed-By: Anna Henningsen <anna@addaleax.net>
rvagg pushed a commit that referenced this pull request Jun 29, 2017
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 <benjamingr@gmail.com>
Original-Reviewed-By: Teddy Katz <teddy.katz@gmail.com>
Original-Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Original-Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Original-Reviewed-By: Timothy Gu <timothygu99@gmail.com>
Original-Reviewed-By: Anna Henningsen <anna@addaleax.net>

PR-URL: #13750
Reviewed-By: Anna Henningsen <anna@addaleax.net>
rvagg pushed a commit that referenced this pull request Jun 29, 2017
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 <luigipinca@gmail.com>
Original-Reviewed-By: Timothy Gu <timothygu99@gmail.com>
Original-Reviewed-By: Gibson Fahnestock <gibfahn@gmail.com>
Original-Reviewed-By: Anna Henningsen <anna@addaleax.net>
Original-Reviewed-By: Refael Ackermann <refack@gmail.com>
Original-Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Original-Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>

PR-URL: #13750
Reviewed-By: Anna Henningsen <anna@addaleax.net>
addaleax pushed a commit that referenced this pull request Jul 11, 2017
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 <benjamingr@gmail.com>
Original-Reviewed-By: Teddy Katz <teddy.katz@gmail.com>
Original-Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Original-Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Original-Reviewed-By: Timothy Gu <timothygu99@gmail.com>
Original-Reviewed-By: Anna Henningsen <anna@addaleax.net>

PR-URL: #13750
Reviewed-By: Anna Henningsen <anna@addaleax.net>
addaleax pushed a commit that referenced this pull request Jul 11, 2017
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 <luigipinca@gmail.com>
Original-Reviewed-By: Timothy Gu <timothygu99@gmail.com>
Original-Reviewed-By: Gibson Fahnestock <gibfahn@gmail.com>
Original-Reviewed-By: Anna Henningsen <anna@addaleax.net>
Original-Reviewed-By: Refael Ackermann <refack@gmail.com>
Original-Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Original-Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>

PR-URL: #13750
Reviewed-By: Anna Henningsen <anna@addaleax.net>
addaleax pushed a commit that referenced this pull request Jul 18, 2017
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 <benjamingr@gmail.com>
Original-Reviewed-By: Teddy Katz <teddy.katz@gmail.com>
Original-Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Original-Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Original-Reviewed-By: Timothy Gu <timothygu99@gmail.com>
Original-Reviewed-By: Anna Henningsen <anna@addaleax.net>

PR-URL: #13750
Reviewed-By: Anna Henningsen <anna@addaleax.net>
addaleax pushed a commit that referenced this pull request Jul 18, 2017
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 <luigipinca@gmail.com>
Original-Reviewed-By: Timothy Gu <timothygu99@gmail.com>
Original-Reviewed-By: Gibson Fahnestock <gibfahn@gmail.com>
Original-Reviewed-By: Anna Henningsen <anna@addaleax.net>
Original-Reviewed-By: Refael Ackermann <refack@gmail.com>
Original-Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Original-Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>

PR-URL: #13750
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
notable-change PRs with changes that should be highlighted in changelogs. semver-minor PRs that contain new features and should be released in the next minor version. util Issues and PRs related to the built-in util module.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

util.callbackify for async functions