Skip to content
Swizec Teller - a geek with a hatswizec.com

My new favourite Javascript trick

Using returns and callbacks in the same function.

Sounds like crazy talk I know, but hear me out, I have good reason. I think.

Let's say you want to make several TCP servers in a node.js application. Have to listen on multiple ports or whatever. Using a factory function is your best bet to avoiding code repetition, right?

You end up with something like this:

var server = function (port, callback) {
var server = net.createServer(function (connection) {});
server.on("connection", function (socket) {
socket.on("data", // data stuff);
socket.on("error", function () {
console.log("error?", arguments);
socket.destroy();
});
socket.on("close", // cleanup stuff);
});
server.on("listening", callback);
server.listen(port);
};

Simple. Call a function, give it a port, get notified when server is ready to listen. Never be able to touch the server again.

Wait, that's not good. What if you want to reference the server later? To close it, for instance.

That's where using returns alongside callbacks comes in.

Just adding a return server at the bottom of that function lets us do something like this:

var make_servers = function (callback) {
this.servers = {};
async.each(
[5000, 5001, 5002],
_.bind(function (port, callback) {
this.servers[port] = server(port, callback);
}, this),
function (err) {
callback();
}
);
return this;
};

I sneakily added the async and underscore libraries because they make life easier.

make_servers will generate three servers listening on ports 5000 to 5002. The async library helped us ensure the main callback is only called once all the servers are ready to listen, and using _.bind let us bind server generation to the current scope.

When this function is done it returns its scope, which now includes references to all the servers, and it will tell your code to keep going when all the servers are ready.

You'd use it something like this:

var stuff = make_servers(function () { // all servers listening });
// stuff.servers can access all servers

If you bind all the callbacks inside server to current scope you can even keep track of connections. You'd end up with something like this:

var server = function (port) {
var server = net.createServer(function (connection) {});
server.on("connection", _.bind(function (socket) {
socket.id = shortid.generate();
this.connections[port][socket.id] = socket;
socket.on("data", // data stuff);
socket.on("error", function () {
console.log("error?", arguments);
socket.destroy();
});
socket.on("close", _.bind(function () {
delete this.connections[port][socket.id];
}, this));
}, this));
return function (callback) {
server.on("listening", callback);
server.listen(port);
return server;
};
};

Not much has changed. More things were bound to this and the return value became a function because I feel partial application makes this code cleaner.

You'd call the server factory like this now: this.servers[port] = server(port)(callback). The main benefit of this approach is that we can generate servers in a loop and activate them at a later time.

We've essentially decoupled server generation and server startup. Might come in handy.

The stuff object from before is now going to have a stuff.connections as well, which references all currently open connections to each port. Neat!

Another trick I sneaked into these examples is Javascript's powerful dynamic scoping. Getting semi-random functions to run in the same scope like that can really clean up your code.

At the expense of being almost too clever sometimes. Use at your own peril.

What do you think, is there a cleaner way to implement something like this?

Did you enjoy this article?

Published on June 26th, 2014 in Callback, Code, JavaScript, Return statement, Server, Uncategorized

Learned something new?
Want to become a high value JavaScript expert?

Here's how it works ๐Ÿ‘‡

Leave your email and I'll send you an Interactive Modern JavaScript Cheatsheet ๐Ÿ“–right away. After that you'll get thoughtfully written emails every week about React, JavaScript, and your career. Lessons learned over my 20 years in the industry working with companies ranging from tiny startups to Fortune5 behemoths.

Start with an interactive cheatsheet ๐Ÿ“–

Then get thoughtful letters ๐Ÿ’Œ on mindsets, tactics, and technical skills for your career.

"Man, love your simple writing! Yours is the only email I open from marketers and only blog that I give a fuck to read & scroll till the end. And wow always take away lessons with me. Inspiring! And very relatable. ๐Ÿ‘Œ"

~ Ashish Kumar

Join over 10,000 engineers just like you already improving their JS careers with my letters, workshops, courses, and talks. โœŒ๏ธ

Have a burning question that you think I can answer?ย I don't have all of the answers, but I have some! Hit me up on twitter or book a 30min ama for in-depth help.

Ready to Stop copy pasting D3 examples and create data visualizations of your own? ย Learn how to build scalable dataviz components your whole team can understand with React for Data Visualization

Curious about Serverless and the modern backend? Check out Serverless Handbook, modern backend for the frontend engineer.

Ready to learn how it all fits together and build a modern webapp from scratch? Learn how to launch a webapp and make your first ๐Ÿ’ฐ on the side with ServerlessReact.Dev

Want to brush up on your modern JavaScript syntax?ย Check out my interactive cheatsheet: es6cheatsheet.com

By the way, just in case no one has told you it yet today: I love and appreciate you for who you areย โค๏ธ

Created bySwizecwith โค๏ธswizec.com