I've refactored a simple utility to use promises. It fetches a pdf from the web and saves it to disk. It should then open the file in a pdf viewer once saved to disk. The file appears on disk and is valid, the shell command opens the OSX Preview application, but a dialog pops up complaining that the file is empty.
What's the best way to execute the shell function once the filestream has been written to disk?
// download a pdf and save to disk // open pdf in osx preview for example download_pdf() .then(function(path) { shell.exec('open ' + path).code !== 0); }); function download_pdf() { const path = '/local/some.pdf'; const url = 'http://somewebsite/some.pdf'; const stream = request(url); const write = stream.pipe(fs.createWriteStream(path)) return streamToPromise(stream); } function streamToPromise(stream) { return new Promise(function(resolve, reject) { // resolve with location of saved file stream.on("end", resolve(stream.dests[0].path)); stream.on("error", reject); }) }
Promises can be used to execute a series of asynchronous tasks in sequential order. Chaining multiple then() methods to a single Promise outcome helps avoid the need to code complicated nested functions (which can result in callback hell).
Readable − Stream which is used for read operation. Writable − Stream which is used for write operation. Duplex − Stream which can be used for both read and write operation. Transform − A type of duplex stream where the output is computed based on input.
Assuming we have the processing power and that our promises can run in parallel, there is a hard limit of just over 2 million promises. If we dig into the code of V8, the JavaScript engine underlying Chrome and Node.
A promise is used to handle the asynchronous result of an operation. JavaScript is designed to not wait for an asynchronous block of code to completely execute before other synchronous parts of the code can run. With Promises, we can defer the execution of a code block until an async request is completed.
In this line
stream.on("end", resolve(stream.dests[0].path));
you are executing resolve
immediately, and the result of calling resolve
(which will be undefined, because that's what resolve
returns) is used as the argument to stream.on
- not what you want at all, right.
.on
's second argument needs to be a function, rather than the result of calling a function
Therefore, the code needs to be
stream.on("end", () => resolve(stream.dests[0].path));
or, if you're old school:
stream.on("end", function () { resolve(stream.dests[0].path); });
another old school way would be something like
stream.on("end", resolve.bind(null, stream.dests[0].path));
No, don't do that :p see comments
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With