-
Notifications
You must be signed in to change notification settings - Fork 29.6k
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
fs: promisify exists correctly #13316
Conversation
test/parallel/test-fs-promisified.js
Outdated
@@ -29,3 +30,5 @@ common.refreshTmpDir(); | |||
fs.closeSync(fd); | |||
})); | |||
} | |||
|
|||
exists(__filename).then((x) => assert(x)); |
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 recommend wrapping these in {}
, too (even if it’s just a single line), and the callback should probably be wrapped in common.mustCall()
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.
done
lib/fs.js
Outdated
@@ -376,6 +376,13 @@ fs.exists = function(path, callback) { | |||
} | |||
}; | |||
|
|||
Object.defineProperty(fs.exists, internalUtil.promisify.custom, { | |||
value: (path) => new Promise((resolve) => | |||
fs.exists(path, (x) => resolve(x))), |
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 could just use resolve
instead of (x) => resolve(x)
, if you like
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.
done
092634c
to
e3d3f3e
Compare
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.
LGTM % 2 nits
test/parallel/test-fs-promisified.js
Outdated
@@ -29,3 +30,7 @@ common.refreshTmpDir(); | |||
fs.closeSync(fd); | |||
})); | |||
} | |||
|
|||
{ | |||
exists(__filename).then(common.mustCall((x) => assert(x))); |
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.
IMHO it's more important to assert:
assert.strictEqual(typeof x, 'boolean')
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 that case you might just strictEqual(x, true)
;)
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.
done, assert.strictEqual(x, true);
lib/fs.js
Outdated
@@ -376,6 +376,12 @@ fs.exists = function(path, callback) { | |||
} | |||
}; | |||
|
|||
Object.defineProperty(fs.exists, internalUtil.promisify.custom, { | |||
value: (path) => new Promise((resolve) => fs.exists(path, resolve)), |
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.
very small nit: place the enumerable: false
before the value
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.
meh, done
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's a style preference.
Thank you for indulging me 🎩
e3d3f3e
to
171a9aa
Compare
lib/fs.js
Outdated
@@ -376,6 +376,12 @@ fs.exists = function(path, callback) { | |||
} | |||
}; | |||
|
|||
Object.defineProperty(fs.exists, internalUtil.promisify.custom, { | |||
enumerable: false, | |||
value: (path) => new Promise((resolve) => fs.exists(path, resolve)) |
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.
Isn't the whole point of promisify NOT to use new 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, the point of promisify is to give users a standard interface for turning Node-style callbacks into functions that return Promises. And since this is a deprecated API, I don’t think there’s a need to micro-optimize.
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.
meh, done. It's now fully micro-optimized 😉
171a9aa
to
8d93e74
Compare
lib/fs.js
Outdated
@@ -376,6 +376,16 @@ fs.exists = function(path, callback) { | |||
} | |||
}; | |||
|
|||
Object.defineProperty(fs.exists, internalUtil.promisify.custom, { | |||
enumerable: false, |
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.
All values in defineProperty
default to false
, so this may not be necessary?
Alternatively, is it intentional that it is not configurable or writable? (I assume at least the latter is true)
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.
AFAIK it's supposed to be "hidden" from userland.
See lib/fs.js#L780
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.
Indeed, I was copying and pasting from line 780, because I incorrectly assumed that enumerable: false
was required to conceal it from userland.
MDN says the defaults are:
{enumerable: false, configurable: false, writeable: false}
Those look like good defaults to me. I'll remove enumerable: false
here and use the defaults. (I guess we should remove it at line 780, but I'll let somebody else do 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.
I like being explicit in code, especially if it helps clarify intent and when the defaults are not obvious to casual readers, which is why I added the enumerable: false
; but I won’t force that on you if you don’t like it.
(@dfabulich Thanks for being so quick with updating here, but just so there’s no confusion: Our opinions aren’t inherently better than yours, and if you think a collaborator makes a request that you don’t agree with, you should feel free to say so.)
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 think all of the proposed changes here have been (small) improvements or no difference to me. I aim to please. :-)
I do think it's about ready to land now.
8d93e74
to
15f3f0b
Compare
PR-URL: #13316 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Vladimir Kurchatkin <vladimir.kurchatkin@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Timothy Gu <timothygu99@gmail.com>
It seems this can be closed now with 65531d0 ? |
Yes, was just getting to that ;-) ... Landed in 65531d0 |
PR-URL: #13316 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Vladimir Kurchatkin <vladimir.kurchatkin@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Timothy Gu <timothygu99@gmail.com>
* **Async Hooks** * When one `Promise` leads to the creation of a new `Promise`, the parent `Promise` will be identified as the trigger [[`135f4e6643`](nodejs@135f4e6643)] [nodejs#13367](nodejs#13367). * **Dependencies** * libuv has been updated to 1.12.0 [[`968596ec77`](nodejs@968596ec77)] [nodejs#13306](nodejs#13306). * npm has been updated to 5.0.3 [[`ffa7debd7a`](nodejs@ffa7debd7a)] [nodejs#13487](nodejs#13487). * **File system** * The `fs.exists()` function now works correctly with `util.promisify()` [[`6e0eccd7a1`](nodejs@6e0eccd7a1)] [nodejs#13316](nodejs#13316). * fs.Stats times are now also available as numbers [[`c756efb25a`](nodejs@c756efb25a)] [nodejs#13173](nodejs#13173). * **Inspector** * It is now possible to bind to a random port using `--inspect=0` [[`cc6ec2fb27`](nodejs@cc6ec2fb27)] [nodejs#5025](nodejs#5025). * **Zlib** * A regression in the Zlib module that made it impossible to properly subclasses `zlib.Deflate` and other Zlib classes has been fixed. [[`6aeb555cc4`](nodejs@6aeb555cc4)] [nodejs#13374](nodejs#13374).
* **Async Hooks** * When one `Promise` leads to the creation of a new `Promise`, the parent `Promise` will be identified as the trigger [[`135f4e6643`](135f4e6643)] [#13367](#13367). * **Dependencies** * libuv has been updated to 1.12.0 [[`968596ec77`](968596ec77)] [#13306](#13306). * npm has been updated to 5.0.3 [[`ffa7debd7a`](ffa7debd7a)] [#13487](#13487). * **File system** * The `fs.exists()` function now works correctly with `util.promisify()` [[`6e0eccd7a1`](6e0eccd7a1)] [#13316](#13316). * fs.Stats times are now also available as numbers [[`c756efb25a`](c756efb25a)] [#13173](#13173). * **Inspector** * It is now possible to bind to a random port using `--inspect=0` [[`cc6ec2fb27`](cc6ec2fb27)] [#5025](#5025). * **Zlib** * A regression in the Zlib module that made it impossible to properly subclasses `zlib.Deflate` and other Zlib classes has been fixed. [[`6aeb555cc4`](6aeb555cc4)] [#13374](#13374).
* **Async Hooks** * When one `Promise` leads to the creation of a new `Promise`, the parent `Promise` will be identified as the trigger [[`135f4e6643`](135f4e6643)] [#13367](#13367). * **Dependencies** * libuv has been updated to 1.12.0 [[`968596ec77`](968596ec77)] [#13306](#13306). * npm has been updated to 5.0.3 [[`ffa7debd7a`](ffa7debd7a)] [#13487](#13487). * **File system** * The `fs.exists()` function now works correctly with `util.promisify()` [[`6e0eccd7a1`](6e0eccd7a1)] [#13316](#13316). * fs.Stats times are now also available as numbers [[`c756efb25a`](c756efb25a)] [#13173](#13173). * **Inspector** * It is now possible to bind to a random port using `--inspect=0` [[`cc6ec2fb27`](cc6ec2fb27)] [#5025](#5025). * **Zlib** * A regression in the Zlib module that made it impossible to properly subclasses `zlib.Deflate` and other Zlib classes has been fixed. [[`6aeb555cc4`](6aeb555cc4)] [#13374](#13374).
Consider this sample code.
Expected: The code should log
true
, because the current file exists.Actual: It logs
oh no true
, as the promise is rejected witherr
set totrue
This is happening because
fs.exists
does not follow the standard format of taking an error-first callback as the last argument. Luckily,util.promisify
provides a.custom
feature for promisifying callbacks that don't follow the nodeback style.In this PR, we provide a custom promise implementation for
fs.exists
.Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
fs