-
-
Notifications
You must be signed in to change notification settings - Fork 33.8k
fs: add support for async iterators to fs.writeFile
#38525
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
base: main
Are you sure you want to change the base?
fs: add support for async iterators to fs.writeFile
#38525
Conversation
675ffcd to
9a563a1
Compare
9a563a1 to
c9bba3f
Compare
lib/fs.js
Outdated
| if (writeErr) { | ||
| if (isUserFd) { | ||
| callback(writeErr); | ||
| } else { | ||
| fs.close(fd, (err) => { | ||
| callback(aggregateTwoErrors(err, writeErr)); | ||
| }); | ||
| } |
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 that in general it would make more sense to continue iterating only after a write has finished.
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.
Agreed. As it is this will have issues with backpressure, risking flooding the destination with pending write requests. Also, I'm missing the bit about exiting the for await if the fs.write() errors on any single iteration.
lib/fs.js
Outdated
| ); | ||
| } | ||
| fs.close(fd, callback); | ||
| })(); |
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.
There's no catch handler on the promise being returned here.
lib/fs.js
Outdated
| } | ||
| // write(fd, buffer, offset, length, position, callback) | ||
| if (isCustomIterable(buffer)) { | ||
| (async () => { |
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 would be clearer and more maintainable to separate this out into a separate top-level function.
lib/fs.js
Outdated
| } | ||
| ); | ||
| } | ||
| fs.close(fd, callback); |
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.
The close here is problematic because writes may still be pending from the loop.
test/parallel/test-fs-write-file.js
Outdated
| process.nextTick(() => controller.abort()); | ||
| } | ||
|
|
||
| { |
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 would be better to separate the tests for the new functionality into a separate isolated test file.
jasnell
left a 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.
It's a good idea but the implementation needs work.
a7cc927 to
3313df8
Compare
3313df8 to
785d76d
Compare
lib/fs.js
Outdated
| if (writeErr) { | ||
| handleWriteAllErrorCallback(fd, isUserFd, writeErr, callback); | ||
| } else { | ||
| writeAll(fd, isUserFd, buffer, offset, |
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 that there's a mistake here that also exists in the fs/promises version, where the code assumes that the whole chunk has been written but it might have only been partially written.
ba733d5 to
ccdb3d1
Compare
ccdb3d1 to
6f21783
Compare
176573e to
c0b87d6
Compare
|
@Linkgoron I added the following test based on this test, but I was not able to reproduce the mistake. 😓 (The current implementation will pass.) |
It's quite difficult to reproduce, and I'm not sure in which cases |
|
@Linkgoron |
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.
There is a lot going on here and I’m not sure I fully agree with all of it. I’m a little bit overloaded the next few days. I won’t block this but would appreciate if we could wait a few days before landing this.
mcollina
left a 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.
Good work! I've left a few notes on the implementation.
| writeAllCustomIterable( | ||
| fd, isUserFd, buffer, offset, length, signal, encoding, callback) | ||
| .catch((reason) => { | ||
| handleWriteAllErrorCallback(fd, isUserFd, reason, callback); |
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 would schedule this via process.nextTick. If this throws synchronously for whatever reason, it will lead to an unhandled rejection.
| }); | ||
| } | ||
|
|
||
| async function writeAllCustomIterable( |
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.
Do not use async with a callback. Mixing those two can only lead to bugs. I would recommend having a promisified version of fs.write() and just use async/await.
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.
@mcollina Thanks for your suggestion 👍 . I'm curious about the advantages of having a promisified version of fs.write() and using async/await. Could you elaborate on why this approach might be better than mixing async with a callback? I'm interested in understanding the potential benefits and how it could prevent bugs.
Fixes: #38075
Checklist