Node

Javascript on the Server

  • Javascript runtime built on Chrome's V8 Javascript engine (now also Edge's Chakra)
  • uses an event-driven, non-blocking I/O model
  • package ecosystem, npm, is the largest ecosystem of open source libraries in the world.
  • enables same language on client and server (YAY!)

Atwood's Law

"Any application that can be written in Javascript, will eventually be written in Javascript."

--Jeff Atwood, 2007

  • Browser
  • Server
  • Desktop (electron, Microsoft apps)
  • Mobile (hybrid apps, etc)
  • CLI (command line interface)
  • IoT (internet of things)

Javascript now exists everywhere:

NPM is the biggest

package manager by far in all the history of package managers

Good

  • Networking applications with a lot of connections
  • Non-blocking IO means multiple requests can be handled on a single thread

Bad

  • CPU intensive calculations
  • Because it is still just javascript, a high level language with garbage collection, etc

Node Performance

Node is single-threaded

Event-driven programming is a programming paradigm in which the flow of the program is determined by events such as

  • user actions (mouse clicks, key presses),
  • sensor outputs, or
  • messages from other programs/threads.

Scaling Node

If node is single-threaded, you might be wondering how to take advantage of multiple core architectures.

Scalability in Node is not an afterthought. It’s something that’s baked into the core of the runtime.

 

Node is named Node to emphasize the idea that a Node application should comprise multiple small distributed nodes that communicate with each other.

separating by data (e.g. by region)

Cloning / Clustering / Load Balancing

using node's built-in cluster module.

separating by function

Decomposing / Microservices

Splitting / Horizontal Partitioning / Sharding

Node Scaling Strategies

If you are lucky enough that your app needs to scale, you may eventually need all three:

Blocking

Non-blocking

const fs = require('fs')

// blocks here until file is read
const data = fs.readFileSync('/file.md') 
const fs = require('fs')

fs.readFile('/file.md', (err, data) => {
  if (err) throw err
})
const util = require('util')
const fs = require('fs')

const readFile 
  = util.promisify(fs.readFile)

readFile('/file.md')
  .then((data) => {
    // Do something with `data`
  })
  .catch((error) => {
    // Handle the error.
  })

via callback (traditional)

 

Non-blocking

via promise (new)

traditional syntax

future syntax

Modules

module.exports = {
  myModule: 'hello world'
}
export const myModule = 'hello world'

my-module.js

my-module.mjs

const myModule 
  = require('./my-module').myModule

console.log(myModule)

parent.js

import { myModule } from './my-module'

console.log(myModule)

parent.mjs

Packages

  • Has a package.json file to specify package metadata and dependencies on other packages
  • May contain 1 or more modules
  • May be published on npm
  • May be consumed as a dependency by other projects

The leftpad problem

module.exports = leftpad;
function leftpad (str, len, ch) {
  str = String(str);
  var i = -1;
  if (!ch && ch !== 0) ch = ' ';
  len = len - str.length;
  while (++i < len) {
    str = ch + str;
  }
  return str;
}

NPM makes it easy to both consume and produce TINY packages. And that can potentially "break the internet"

Are tiny packages bad?

Short answer: NO!

Code reuse and reducing

cognitive load for developers is a very good thing.


However, there are some caveats:

  • Security
  • Third party deps can break in the future
  • Potentially some tiny perf overhead
  • You forget how to be a "real programmer" (just kidding! lol)

Node

By Jason Sewell