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

Adding Core support for Promises #5020

Closed
wants to merge 33 commits into from
Closed
Changes from 1 commit
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
c1613c0
internal: add {callback,promis}ify.js
chrisdickinson Feb 1, 2016
a8efd4f
zlib: promisify
chrisdickinson Feb 1, 2016
4af7ec2
repl: promisify
chrisdickinson Feb 1, 2016
0e0a2d9
readline: promisify .question + callbackify completer
chrisdickinson Feb 1, 2016
8798a26
build: add callbackify and promisify to node.gyp
chrisdickinson Feb 1, 2016
355205b
net: promisify socket.setTimeout; add connectAsync
chrisdickinson Feb 1, 2016
7b8e57d
internal: fixup promisify
chrisdickinson Feb 1, 2016
3f2b0d8
http,https: add {request,get}Async
chrisdickinson Feb 1, 2016
23ba073
fs: no callback -> return promise
chrisdickinson Feb 1, 2016
68837b8
dns: promisify
chrisdickinson Feb 1, 2016
3317652
dgram: promisify .{bind,close,send}
chrisdickinson Feb 1, 2016
846bd49
doc,dgram: add promise notes to dgram docs
chrisdickinson Feb 1, 2016
d90b42c
internal: add hooks for specifying different promise resolver
chrisdickinson Feb 1, 2016
adbe352
crypto: promisify pbkdf2, add randomBytesAsync
chrisdickinson Feb 1, 2016
697ce01
child_process,cluster: promisify .send(), add exec{File,}Async
chrisdickinson Feb 1, 2016
f36b62d
add process.setPromiseImplementation
chrisdickinson Feb 1, 2016
082fa08
process: add setPromiseImplementation API
chrisdickinson Feb 1, 2016
54e3001
tls,net: connectAsync should resolve to Socket
chrisdickinson Feb 1, 2016
014fb3e
lib: repromisify
chrisdickinson Feb 2, 2016
15a42c1
repromisify
chrisdickinson Feb 2, 2016
8586b10
src,lib: move back to native promises
chrisdickinson Feb 2, 2016
40ca55e
domain,promise,src: add shim to make promises work with async_wrap + …
chrisdickinson Feb 2, 2016
3928beb
domain: promises capture process.domain at .then time
chrisdickinson Feb 2, 2016
fa725b3
src: back asyncwrap integration out of this pr
chrisdickinson Feb 2, 2016
0528d74
internal: lint
chrisdickinson Feb 3, 2016
010224a
http{,s}: getAsync only listens for error once
chrisdickinson Feb 5, 2016
6ae09c5
http{s,}: nix {request,get}Async
chrisdickinson Feb 10, 2016
670a9c2
rework promisifier
chrisdickinson Feb 10, 2016
240c72d
src: add flag
chrisdickinson Feb 10, 2016
565dfe2
fix handler
chrisdickinson Feb 11, 2016
3384ab0
introduce .promised
chrisdickinson Feb 11, 2016
4e38057
bugfix: use outer arguments
chrisdickinson Feb 11, 2016
8c97549
wip: add recovery object
chrisdickinson Feb 11, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
wip: add recovery object
  • Loading branch information
chrisdickinson committed Feb 11, 2016

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
commit 8c975499a951779c115dc2998d8df1b2976d22fa
21 changes: 17 additions & 4 deletions lib/internal/promisify.js
Original file line number Diff line number Diff line change
@@ -11,23 +11,35 @@ module.exports = {
};

function normal(object, name) {
return _promisify(object, name, (err, val) => {
return _promisify(object, name, (lastArg, err, val) => {
if (err) {
if (lastArg &&
typeof lastArg === 'object' &&
err.code &&
typeof lastArg[err.code] === 'function') {
return lastArg[err.code]()
}
throw err;
}
return val;
});
}

function single(object, name) {
return _promisify(object, name, (val) => {
return _promisify(object, name, (lastArg, val) => {
return val;
});
}

function multiple(object, name, mapped) {
return _promisify(object, name, (err, arg0, arg1) => {
return _promisify(object, name, (lastArg, err, arg0, arg1) => {
if (err) {
if (lastArg &&
typeof lastArg === 'object' &&
err.code &&
typeof lastArg[err.code] === 'function') {
return lastArg[err.code]()
}
throw err;
}
return {
@@ -42,12 +54,13 @@ function _promisify(object, name, handler) {

function inner() {
const args = Array.from(arguments);
Copy link

Choose a reason for hiding this comment

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

Isn't this optimization killer?

Copy link

Choose a reason for hiding this comment

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

yes, to avoid it copy the arguments manually with a for loop.

const args = new Array(arguments.length);
for (let i = 0; i < arguments.length; i++) {
  args[i] = arguments[i];
}

Copy link
Member

Choose a reason for hiding this comment

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

Function can be already deopted because of try-catch below, so ¯_(ツ)_/¯

Copy link

Choose a reason for hiding this comment

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

yep, that probably needs moving into a specialist attempt function which only does the try...catch and returns the result.

Copy link
Member

Choose a reason for hiding this comment

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

Or we can just not care about those kinds of optimizations as function is already just a wrapper for another one :) (and V8 compilers change over time, too)

Copy link

Choose a reason for hiding this comment

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

Function can be already deopted because of try-catch below, so ¯_(ツ)_/¯

Seems like it's not an issue anymore with the latest V8: https://twitter.com/kdzwinel/status/667078434598682624

function is already just a wrapper for another one

And this is exactly what bothers me: it's used as a wrapper for all promised API. But, as someone pointed above, IO is so extremely slow that this deopt may not affect overall performance. So more likely you're right, but it would be nice to do at least some basic benchmarking. Just in case 😉

Copy link
Member

Choose a reason for hiding this comment

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

Seems like it's not an issue anymore with the latest V8

That's why I said "compilers change over time" (but, as far as I remember, they co-exist now and try-catch will be fast only under certain conditions). Anyway, great to see progress - and with more engines coming, I'm pretty sure we don't need to care neither about deopts nor about "we will slow down callbacks if check whether they're passed or not" - this is I/O after all.

const lastArg = args[args.length - 1];
return new Promise((resolve, reject) => {
fn.call(this, ...args, resolver);

function resolver(arg0, arg1, arg2) {
try {
resolve(handler(arg0, arg1, arg2));
resolve(handler(lastArg, arg0, arg1, arg2));
Copy link
Contributor

Choose a reason for hiding this comment

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

This reminds me of cases where I do something like cb(null, JSON.parse(blob)) and the cb throws rather than the JSON.parse and I get confused and angry. This might not be an analogous case (would you ever expect resolve to throw ever?) but I figured I'd make note of it.

Copy link
Member

Choose a reason for hiding this comment

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

@jfhbrook yes, promises normalize that - if you pass JSON.parse to a promise or async method you'll get consistent behavior somePromiseFn().then(JSON.parse) does not result in a synchronous throw - but rather an asynchronous rejection. If you don't handle it you get an unhandledRejection but it is recoverable. This also has the benefit of catching any places you forgot to deal the error case. For example, with promises you don't have to explicitly type if(err) return cb(err); (and forget the return :P). With promises every error path is checked and propagated - like in completely synchronous code.

} catch (err) {
reject(err);
}