add promises API#171
Conversation
|
I suggest replacing the trailing |
|
@Moriarty47 thanks for the suggestion! Is this recommendation coming from a precedent somewhere? I see the parallels with node's In contrast to |
|
@thejoshwolfe Hmm... you're right. For Node, asynchronous non-blocking behavior is the primary concern, so Alternatively, you could follow the |
I'm glad to hear someone's opinion on that design. I find it baffling that you have the same names of functions with different semantics. Baffling doesn't mean bad, and I might just be out of the loop with modern JS programming idioms. I suppose typescript linters will help you not confuse the two? I definitely don't want to have two APIs where the only difference is the control flow paradigm. That's just too hard for me to stomach. In terms of the actual semantics of the two paradigms:
If we were designing both at the same time, it'd probably be best to make the Promise version the default name, and call the callback parameter version something unusual. (Or rather just don't even make the callback version, because you can transform a Promise into the old style of callbacks pretty easily.) But since we have to name the Promise version something different... I believe the term
My project is far too small to try to establish naming conventions (for a 9 year old JavaScript paradigm, lmao). But the term |
|
Thanks for your time and the detailed discussion. Nearly 4 million downloads per week is not a “small project.” : ) And sorry, I still don’t fully get it:
...As I write this I think I understand your point: you named it After looking at your changed code, I found many implementations like this. function openPromise(path, options) {
return new Promise((resolve, reject) => {
open(path, {...options, lazyEntries: true}, function(err, zipfile) {
if (err) return reject(err);
resolve(zipfile);
});
});
}I think it can be done directly with built-in functions const { promisify } = require('node:util');
const promisifiedOpen = promisify(open);
function openPromise(path, options) {
return promisifiedOpen(path, {...options, lazyEntries: true});
}Thanks again for your time and effort. |
Right. Since i'm not using
Right. The function returns a
I am aware of the promisification facilities availble in node, but it's unnecessary complexity. The docs on that function include 5 paragraphs of discussion and links/references 2 more sections with 6 more paragraphs. Here is the source code for just the All that's unnecessary complexity compared against a cool 8 lines of code per promisification in my own code. Also, some users have expressed interest in porting yauzl to non-node environments (like the browser), and i have to imagine that avoiding node-specific builtins makes that easier, but i haven't tried going through the process myself, so this advantage is speculative. |
|
Okay, got it. You're right, I think I fell into the trap of over-engineering. Keep it simple, reduce unnecessary complexity. simple, readable, and easy-to-change code is the correct practice. I'm glad we talked so much, and I learned a lot. Thank you so much for your time and patient answers. |
|
Thanks for this, this really simplifies and improves the API ❤️ For example, XhmikosR/decompress-unzip#2 |
yauzl roars into the year 2017 with the addition of promises and proper async/await support!
openPromise(),fromFdPromise(),fromBufferPromise(),fromRandomAccessReaderPromise(),openReadStreamPromise(),readLocalFileHeaderPromise(),openReadStreamLowLevelPromise().eachEntry(), which gives async iterator semantics as an alternative toreadEntry(),Event: "entry",Event: "end", andEvent: "error".README.mdandexamples/usingawaiton the new APIs.This is the new recommended usage at the top of the readme:
All the old APIs work the same. This PR only adds new alternative ways of calling things.
Why now? Why not earlier? Why at all?
My intent with spending so much effort over the years polishing yauzl to be as high quality as it's been, is that yauzl can be "done" kinda, as far as node.js software goes. I can be pretty confident that this library is as useful now as it was 10 years ago, and will be for the next 10 years. Adding first-class integration with fancy new language features is not necessary, because this is a solved problem. Only if the old way of doing things breaks out from under me do I have to do anything, such as with the
destroy()method, or the deprecated buffer constructor.So that's why I never bothered to add promise semantics before this. I stopped writing any significant amount of node.js software myself years ago, so I'm not the one demanding the feature. And if nothing's broken, then there's nothing to fix.
However, while debugging #169, I was kinda forced to play around with async/await, promises, async iterators, etc., and I was impressed by just how easy it all was. After I wrote the code to repro the issue, I figured I might as well integrate the code into the core library and properly support it forever.
And yeah, who'd have thought. The modern
awaitstyle usage of the API is actually much nicer than the legacy callbacks style. It's terser for sure, and I'd bet it's harder to get wrong, although that's really up to the client authors.This does complicate the API surface area of yauzl and thereby the testing burden, which is evident from all the warnings around mixing
readEntry()andeachEntry(). But it seems worth it.