Modern Server Side Development with
NodeJSWhat changed since the 0.10 days
Benjamin Gruenbaum
Benjamin Gruenbaum• I work @ TipRanks• NodeJS core collaborator.• Promises guy, bluebird fan and core contributor.• I argue with people online.• StackOverflow guy.
This talk is in 3 partsThe Past
The PresentThe Future
Let’s go back to 2009
JavaScript on the Server
JavaScript on the server is an old idea
Netscape Enterprise Server – 1995Steve Yegge’s Server – 2008
JavaScript on the server is a good idea?
Remember, 2008- JavaScript engines are painfully slow.APIs were nonexistent.Language was hated.
Suddenly – V8Google needed fast JavaScript in Chrome –
so JavaScript engines became fast.
This Ryan guy thought… let’s make a non-blocking server.
As in – no thread “block”s in the user server code.
What can we write this in?
We need a language that doesn’t have file/net APIs yet to get a sane ecosystem.
JavaScript has no blocking APIs
The Result – solving “The 10K
Problem”
How: The Event LoopThreads and OS non-blocking APIs push things into queues
User code runs on a single thread and executes handlers on the queues
Why even write node?It’s fast enough.
Why even write node?Server and client in one language
Why even write node?It was cool
Remember: in 2009 JS is all the hotness
Code Sample: Chat Servernet.createServer(function(socket) { var user = users.add(socket) socket.on('data', function(data) { <- Callback user.sendOthers("> " + data) }); socket.on('close', function(hadError) { <- Callback user.leave(); });}).listen(8000);
Ryan joined Joyent, which looked over
Node
Initially, things worked well – Node got traction
But… Stagnation started.
No new ES features, even when available in Chrome.
Fast Forward to last year
NodeJS was forked into Io.js
Goal: Modern V8
Goal: Modern APIs
Goal: Inclusivity
Goal: Adopt modern JS
Eventually, io.js won. The projects merged.
The result of the io.js fork:Modern V8 version.
NodeJS on top of the io.js fork rather than the Joyent repo.
Handing over of the Joyent repo to the NodeJS foundation.
Community governance. Lots of new features for the community.
Just how different is Node today?
Current version: Node 7+Node 0.12 – last yearfunction persistCriticalFile(cb) { fs.readFile("criticalFile", function(err, data) { if(err) return cb(err); db.persist("collection", process(data), function(err, result) { if(err) return cb(err); cb(null, result); }); });}
Current version: Node 7+Node 7 – this year
async function persistCriticalFile(cb) { const data = await fs.readFileAsync("criticalFile"); return await db.persistAsync("collection", process(data));}
So – how do we develop with Node 7?Let’s look at a simple scenario. You want to get the comments to a post on your site.
- First, from the cache if they’re there. - If they’re not, from the database.
So – how do we develop with Node 7?
Node 0.x:app.get('/getComments/:userId', function(req, res){ var userId = req.params.userId; commentCache.get(userId, function(err, data) { if(err) { instrumentation.log(err); return res.json(err); } if(data) return res.json(data); db.getCommentsByUserId(userId, function(err, data) { if(err) { instrumentation.log(err); return res.status(500).end(err); } cache.store(data, function() {}); return res.json(data); }); });
});
So – how do we develop with Node 7?
Node 0.x:app.get('/getComments/:userId', function(req, res){
var userId = req.params.userId; commentCache.get(userId, function(err, data) { if(err) { instrumentation.log(err); return res.json(err); } if(data) return res.json(data); db.getCommentsByUserId(userId, function(err, data) { if(err) { instrumentation.log(err); return res.status(500).end(err); } cache.store(data, function() {}); return res.json(data); });
});});
So – how do we develop with Node 7?
Node 0.x:app.get('/getComments/:userId', function(req, res){ var userId = req.params.userId; commentCache.get(userId, function(err, data) {
if(err) { instrumentation.log(err); return res.json(err); } if(data) return res.json(data); db.getCommentsByUserId(userId, function(err, data) { if(err) { instrumentation.log(err); return res.status(500).end(err); } cache.store(data, function() {}); return res.json(data); }); });});
So – how do we develop with Node 7?
Node 0.x:app.get('/getComments/:userId', function(req, res){ var userId = req.params.userId; commentCache.get(userId, function(err, data) { if(err) { instrumentation.log(err); return res.json(err); }
if(data) return res.json(data); db.getCommentsByUserId(userId, function(err, data) { if(err) { instrumentation.log(err); return res.status(500).end(err); } cache.store(data, function() {}); return res.json(data); }); });});
So – how do we develop with Node 7?
Node 0.x:
db.getCommentsByUserId(userId, function(err, data) { if(err) { instrumentation.log(err); return res.status(500).end(err); } cache.store(data, function() {}); return res.json(data); }); });
So – how do we develop with Node 7?
app.get('/getComments/:userId', ({params: {userId}}, res) => { const fromCache = await commentCache.get(userId); if(fromCache) return res.json(fromCache); const fromDb = await db.getCommentsByUserId(userId); res.json(fromDb); commentCache.store(userId, fromDb);});
How our flow has changed: tests
Old
it("does something", function(done) { myApi("someData", function(err, result) { assert.equal(err, null); assert.equal(result === 3); done(); });});
New
it("does something", async () => { assert.equal(await myApi("someData", 3)); });
How our flow has changed: classes
Old
function User(id) { this.id = id; } User.prototype.foo = function(id){ doBar(id); }
New
class User { constructor(id) { this.id = id } foo() { doBar(id); } }
How our development flow changed.• Hot reload servers in JS• Node first approaches in client side flows• The rise of universal JS
How our web flow changed.• Rest vs. GraphQL/Falcor.• Native debugger.• Handling request/response cycles.• How express changed.• How clustering changed.
How production changed.• The rise of containers.• More people into node.• Community got a lot bigger, a lot more mature.• Node backed by major companies.• Node for IoT, node on Chakra.
What’s coming next?
Async Iteratorsasync function* map(fn) { // async + generator, great stream processing for await(const value of this) yield fn(value); };
Observables
Core API Promises
node –expose-wasm
ES Modulesimport {some, other} from "module name"
libuv.jsLower level NodeJS
Code?
Just a few words about open source
You don’t have to be an expertWe’ll onboard you
Node is actively looking…
Questions?The Past
The PresentThe Future
Thank You