Gzip Compression with NodeJS – zlib.gzip()
The zlib module is a little bit quirky, and the zlib.gzip method is no exception. Instead of returning the result like a civilized method, an asynchronous callback was built into the method itself.
var zlib = require('zlib');
typeof zlib.gzip('Hello, world!') === 'undefined';
true
Instead, you have to create a callback method that accepts two arguments: error, and result. As you can see below, even returning the result to the callback doesn't return the result to the parent function – which, in my opinion, it should.
var zlib = require('zlib');
typeof zlib.gzip('Hello, world!', function (error, result) {
if (error) throw error;
return result;
}) === 'undefined';
true
Regardless, the author's intended implementation works as advertised.
var zlib = require('zlib');
zlib.gzip('Hello, world!', function (error, result) {
if (error) throw error;
console.log(result);
})
<Buffer 1f 8b 08 00 00 00 00 00 00 03 f3 48 cd c9 c9 d7 51 28 cf 2f ca 49 51 04 00 e6 c6 e6 eb 0d 00 00 00>
Written by Christian Bundy
Related protips
3 Responses
NodeJS is all about async methods that invoke callbacks upon completion. The typical pattern for NodeJS APIs is exactly what you describe: the last arg is a callback function, the callback will be invoked with the first param being either null or some error value, and optionally more callback arguments to provide the result of the async operation. Use of callbacks instead of synchronous return values is one of the biggest learning curves for newcomers to Node, especially if you are a UI dev specializing in browser hosted Javascript.
Don't worry, the async callback thing will eventually seem natural. There are also good libs like async
and q
to help avoid Node "callback hell". Node's use of callbacks is what makes Node scale pretty darn well with I/O bound operations.
Thanks @steve-jansen!
Instead of adding an argument for the callback function, wouldn't it make more sense to return the value in a try...catch block? For example:
try {
console.log(zlib.gzip('Hello, world!'));
} catch (e) {
throw e;
}
You're completely right, I'm a UI dev and I've only ever used Javascript in the browser – it just seems like adding callback arguments to NodeJS methods adds cruft to methods that could easily be implemented with native functionality. Thanks for taking the time to help me understand!
Hi @christianbundy,
I recommend any of the great blog posts out there explaining pros and cons of the NodeJS event loop, like Node's own about page.
In a nutshell, Node uses an event loop for concurrency instead of the more common approach with multiple operating system threads. In Node, a thread should never sit idle waiting for I/O to complete. This enables a server to handle concurrent tasks using a single operating system thread. Node's position is threads are hard to code well and are expensive runtime resources, so avoiding multiple threads makes coding much simpler and more scalable at runtime.
The practical implementation of this approach is the callback pattern you described. An I/O function call initiates the work, and Node moves on to the next task in the event queue. When the I/O completes, your callback is queued on the Node event loop, and subquently invoked by Node to let you know the I/O is done and optionally tell you about any errors or results.
There are many criticisms of Node (like this famous one), however, I am amazed at what Node can accomplish in a few hundred lines of code compared to what was possible a decade ago.
Enjoy learning Node!