Node.js

Created by Maksym Tarasenko

Agenda

  • Node Basics
  • Express.js
  • Mongo/Mongoose
  • SOCKET.IO

Node Basics: What is node?

  • v8 javascript engine
  • Event drivin
  • Non-blocking standart libraries
  • C\C++ adons
  • NPM

Node Basics: JavaScript Everywhere

  • Code reuse (minimal)
  • Same programming culture on client and server
  • Lots of JavaScript programmers

Node Basics: Vibrant Community

  • 340,000+ packages on npm
  • Top corporate sponsors
  • Huge wealth of JS code

Node Basics: Sweet Spots

  • Real-time/high concurrency apps (I/O Bound)
  • API tier for single-page apps and rich clients (iOS, Android)
  • Service orchestration
  • Working with document (JSON-style) databases

Event Loop

Event Loop

Event Loop

Event Loop

Event Loop

Modules

  • Prevents pollution of the global scope
  • Module structure
  • module.exports
  • Caching

Modules: require

var module1 = require('module1'); var module1 = require('./node_modules/module1/index.js'); var module2 = require('./module2'); var module3 = require('../module3');

Modules:

exports.log = function(msg) { console.log(msg); } module.exports = function Loger() { this.log = function(msg) { console.log(msg); } };

NPM

  • package.json
  • npm init
  • npm install
  • npm publish

package.json (1)

{
	"name": "3_npm_test",
	"version": "1.0.0",
	"description": "test package",
	"main": "main.js",
	"scripts": {
		"test": "echo \"Error: no test\" && exit 1",
		"runMain": "node main.js"
	}
}

package.json (2)

{
	"repository": {
		"type": "git",
		"url": "git+https://github.com/itmoh/node-mentoring.git"
	},
	"keywords": [
		"node"
	],
	"author": "maxim tarasenko",
	"license": "ISC",
	"bugs": {
		"url": "https://github.com/itmoh/node-mentoring/issues"
	},
	"homepage": "https://github.com/itmoh/node-mentoring#readme"
}

Some Commands

  • npm init
  • npm install [--save] [--save-dev] [-g]
  • npm run some_command
  • npm adduser
  • npm publish
  • npm version

test_1

Acync Code

  • Node-style
  • Promises (Q)
  • Async
  • Generators(ES6)

Node-style

var someModule = require('./some_module'); someModule.sum({ x: 1, y: 2 }, function(err, result) { if (err) { console.log(err); return; } console.log(result); });

Promises (Q)

var someModule = require('./some_module'); var qSum = Q.denodeify(someModule.sum); Q({ x: 1, y: 2 }) .then(qSum) .then(function(result) { console.log(result); }) .catch(function(error) { console.log(error); });

Async

var async = require('async'); var someModule = require('./some_module'); async.waterfall([ function(callback) { callback(null, { x: 1, y: 2 }); }, someModule.sum, function(result, callback) { console.log(result); }, ], function (err, result) { console.log(err); });

Generators(ES6)

var Q = require('Q'); var co = require('co'); var someModule = require('./some_module'); var qSum = Q.denodeify(someModule.sum); function* test() { try { var result = yield qSum({x: 1, y: 2}); console.log(result); } catch(err) { console.log(err); } }; co(test);

Streams

Events

var EventEmitter = require('events'); var emitter = new EventEmitter(); var listener = (arg) => {console.log(arg);}; emitter.on('test', listener); setTimeout(function() { emitter.emit('test', 'Hello world'); emitter.removeListener('test', listener); emitter.emit('test', 'Hello world'); }, 1000);

fs + http

var http = require('http'), fs = require('fs'); http.createServer(function(request, response) { if (req.method === 'POST') { fs.readFile('./data.csv', 'utf-8', function(err, data) { response.end(data); }); } else res.end('send me a POST\n'); }).listen(3000);

test_2

Development & Debug

  • nodemon, pm2
  • node-inspector

Express.js

  • Middleware
  • Routing
  • Templating

Middleware concept

var express = require('express'); var app = express(); app.use(bodyParser.json()); app.use(function (req, res, next) { console.log('Time:', Date.now()); next(); }); app.get('/user', function(req, res) { res.send('hello user'); }); app.listen(3000, function () { console.log('Example app listening on port 3000!'); });

Routing

  • Respond to HTTP requests with a callback
  • Supports variable placement in routes
  • Easy to serve JSON
  • Routing filter types

Routing

app.get('/', function (req, res) {}); app.post('/:id', function (req, res) {}); var express = require('express'); var router = express.Router(); router.put(/\/abc|\/xyz/, function (req, res) {}}); router.delete(['/', '/:id'], function (req, res) {});

Templating

app.set('view engine', 'ejs'); app.locals.title = 'My App'; app.get('/', function (req, res) { res.locals.someText = 'test'; res.render('test', { message: 'Hello there!'});; });

test_3

MongoDB Basics

  • DataBase
  • Collection
  • Document
  • Field

Create

db.unicorns .insert({ name: 'Aurora', dob: new Date(1992,2,13,7,47), loves: ['carrot','papaya'], weight: 600, gender: 'm', vampires: 63 });

Find

db.unicorns.find({gender: 'm', weight: {$gt: 700}}) db.unicorns.find({gender: {$ne: 'f'}, weight: {$gte: 701}}) //$lt, $lte, $gt, $gte, $ne, $or db.unicorns.find({ gender: 'f', $or: [ {loves: 'apple'}, {loves: 'orange'}, {weight: {$lt: 500}} ]}) //Projection db.unicorns.find({vampires: {$exists: false}}, { name:1, _id: 0}) .skip(2) .limit(5) .sort({name:1})

update

db.unicorns.insert({}) db.unicorns.insert([{}, {}]) db.unicorns.update( {gender: 'm'},// selector { $set: {loves: "grape"}, $currentDate: {dob: true} },//update { multi: true, upsert: true } ) // remove all db.unicorns.remove({}) // remove match condition db.unicorns.remove({type: "food"}) // remove match condition only one db.unicorns.remove({type: "food"}, 1)

ORM-way: Mongoose

  • SCHEMA
  • MODEL
  • Fields types

Connection

var mongoose = require('mongoose'); mongoose.connect('mongodb://localhost/test'); var db = mongoose.connection; mongoose.Promise = require('q').Promise; db.on('error', function(err) { console.error('connection error:', err)); }); db.once('open', function (callback) { console.log('connected'); });

MODEL

var mongoose = require('mongoose'); var Schema = mongoose.Schema; var RolesSchema = new Schema({ role: { type: String, required: true }, date: {type: Date, default: Date.now}, members: [{ type: String }] }, {collection: 'roles'}); module.exports = mongoose.model('Roles', RolesSchema);

MODEL

RolesSchema.methods.findAllMembersRoles = function () { return this.model('Roles').find({members: this.members}); } RolesSchema.statics.findByName = function (name) { return this.find({role: new RegExp(name, 'i')}); } RolesSchema.virtual('membersAll') .get(function () { return this.members.join(','); }) .set(function (members) { var membersArray = members.split(','); this.members = membersArray; });

Work with model: Save

var newModel = new model({ role: 'dev', members: ['user1', 'user3'] }); newModel.save(function (err) { if (err) return handleError(err); saved! }); newModel.save() .then() .catch()

Work with model: Find

model.find({role: 'dev'}) .skip(skip) .limit(limit) model.findById(id) .then(function (modelInstance) { var updatedInstance = _.extend(modelInstance, req.body); return updatedInstance.save(); })

Work with model: Find

model.remove({role: 'dev'}) model.update({ role: 'dev' }, { $set: {members: ['user2']} })

test_4

REALTIME

  • Periodic Polling
  • Long Polling
  • Forever Frame
  • WebSockets

SOCKET.IO

var io = require('socket.io')(8080); io.on('connection', function (socket) { socket.emit('greet', { hello: 'world' }); socket.on('message', function (from, msg) { console.log('message by ', from, ' saying ', msg); }); socket.on('disconnect', function () { socket.emit('user disconnected'); }); });

SOCKET.IO

<script src "/socket.io/socket.io.js"></script> <script> var socket = io('http://localhost:8080'); socket.on('greet', function (data) { console.log(data); socket.emit('message', 'user', 'hello'); }); </script>

BROADCAST & VOLATILE

var io = require('socket.io')(8080); io.on('connection', function (socket) { socket.broadcast.emit('new user connected'); }); var io = require('socket.io')(8080); io.on('connection', function (socket) { var tweets = setInterval(function () { getCatsTweets(function (tweet) { socket.volatile.emit('cats tweet', tweet); }); }, 100); socket.on('disconnect', function () { clearInterval(tweets); }); });

Questions?