Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare a Scribd company logo
Введение в технологию
От JavaScript никуда не деться 
«Всё, что может быть написано на JavaScript, 
должно быть написано на нём» 
«Any application that can be written in JavaScript, 
will eventually be written in JavaScript» 
Jeff Atwood 
основатель Stack Overflow
Основные идеи Node.js 
1. Один язык, один формат данных, 
одна парадигма, одна архитектура 
СУБД 
Мобильные 
приложения 
Сервер 
Браузер 
Оконные 
приложения 
JSON 
BSON 
JavaScript 
JavaScript 
JavaScript
Основные идеи Node.js 
2. Долгая жизнь приложений в 
оперативной памяти на стороне сервера 
• Состояние памяти сохраняется между запросами 
• Структуры данных (объекты, модель) 
• Соединения с БД и открытые файлы 
• Конфигурация и инициализация 
• Веб сервер внутри приложения, а не наоборот 
• Меньше IPC
Основные идеи Node.js 
3. Без ввода/вывода еще быстрее, 
чем с асинхронным вводом/выводом 
• Упреждающее чтение 
• Отложенная запись 
• Отдача всего из памяти
Преимущества JavaScript: 
1. Имеет очень низкий порог входа; 
2. Высочайшая гибкость; 
3. Высокая скорость разработки; 
4. Практически идеальный уровень 
абстракции; 
…
Недостатки JavaScript: 
1. Имеет очень низкий порог входа; 
2. Высочайшая гибкость; 
3. Высокая скорость разработки; 
4. Практически идеальный уровень 
абстракции; 
…
Особенности JavaScript 
Наличие огромного количества особенностей. 
Как в синтаксических конструкциях, так и в 
логике программ. 
“12” + 5 === “125” 
Но… 
“12” - 5 === 7 
[] + [] === “” 
[] + {} === “[object Object]” 
{} + [] === 0 
isNaN({} + {}) === true
Введение в NodeJS
Что такое NodeJS 
• Open Source JavaScript-движок V8 от Google; 
• Обёртка и библиотеки на JavaScript; 
• libuv; 
• Оболочка, написанная на C++.
Google V8 
• Разработка Google, исходный код которой был 
открыт в 2008 году; 
• Самый оптимальный JavaScript-движок на 
сегодняшний день; 
• Основа браузеров Google Chrome и Chromium.
Преимущества V8 
• Базовый и оптимизирующий компилятор; 
• Компиляция JavaScript-кода непосредственно в 
машинный код, без промежуточного байт-кода; 
• Эффективная система управления памятью; 
• Введение скрытых классов и встроенных кэшей, 
ускоряющих доступ к свойствам и вызовы 
функций.
Начало работы с NodeJS 
1. Установка дистрибутива с nodejs.org; 
2. Создание *.js файлов; 
3. Запуск программ: $ node *.js;
Элементарный пример 
hello.js: 
console.log(“Hello, world!”); 
$ node hello 
Hello, world!
API, менеджер пакетов и package.json 
$ npm init 
… 
$ npm install colors --save 
/ 
/node_modules 
/colors 
... 
main.js 
package.json 
net 
https 
buffer 
crypto 
path 
…
package.json 
{ 
"name": "Test", 
"version": "1.0.0", 
"description": "", 
"main": "index.js", 
"scripts": { 
"test": "echo "Error: no test specified" && exit 1“ 
}, 
"author": "", 
"license": "ISC" 
}
Система контроля версий 
• Git; 
• GitHub; 
• Структура проектов; 
• Репозитории npm; 
• Командная работа.
Специфика NodeJS
Однопоточность и многопоточность 
• Что дает однопоточность? 
• Действительно ли 1 процесс = 1 поток? 
• Как нагрузить все ядра? 
• cluster = require('cluster') 
• npm install webworker-threads 
• самостоятельно делаем IPC
Межпроцессовое взаимодействие 
• Родное IPC, cluster 
• Разделяемая память: Memcache? 
• Шина сообщений (MQ): ZeroMQ, RabbitMQ... 
• TCP, UDP, HTTP
Асинхронный ввод/вывод 
• Реактор 
• Очередь 
• СМО 
fs.readFile( 
‘a.txt’, 
onRead 
); 
http.get( 
‘http://...’, 
onGet 
); 
console.log(‘done?’);
Производительность 
• Производительность кода 
• Производительность сервера 
Факторы производительности Node.js 
• Асинхронность 
• Состояние в памяти 
• Минимизация IPC
Память 
• GC (RAM 32bit: 512Mb, 64bit:1.7Gb ) 
• node --max-old-space-size=3000 
• delete obj.field; delete arr[5]; delete name; 
• node --nouse-idle-notification 
--expose-gc application.js 
• Вызываем gc();
Профилирование 
• npm install -g node-inspector 
node --debug application.js 
• npm install heapdump 
var hd = require('heapdump'); 
hd.writeSnapshot( 
'dump'+Date.now()+'.heapsnapshot' 
);
Отладка 
• Через node-inspector 
• Выводом в консоль console.log(); или в лог 
• Если ошибку не видно 
• node --stack-trace-limit=1000 application.js 
• Может понадобиться фильтр
Ошибки 
• Общепринято в Node: function(err, arguments...) 
• Создаем new Error('Eror message') 
• Секция try {...} catch(e) {...} finally {...} 
• Событие .on('error', fn) если EventEmitter 
• Домены domain.create(); .run(fn); .on('error', fn); 
• Перехват 
process.on('uncaughtException', function(err) { 
console.log('uncaught Exception: '+err.stack); 
});
Обновление кода и перезапуск 
• Наблюдение за процессом forever 
npm install forever -g 
forever start --spinSleepTime 10000 application.js 
• Наблюдение за файлами 
http://livereload.com/ 
http://habrahabr.ru/post/168091/
Callback’и и вложенность 
Пример запроса: 
request('http://www.google.com/api', 
function (error, response, body) { 
var googleData = JSON.parse(body); 
... 
} 
);
Callback’и и вложенность 
request('http://www.google.com/api', 
function (gError, gResponse, gBody) { 
request('http://www.yandex.com/api', 
function (yError, yResponse, yBody) { 
request('http://www.twitter.com/api', 
function (tError, tResponse, tBody) 
{ 
... 
} 
...
Callback’и: Библиотека async 
async.parallel([ 
function(){ ... }, 
function(){ ... } 
], callback); 
Другие методы: series, parallel, whilst, until, 
waterfall, compose, queue, cargo, retry, each, map, 
reduce, detect, every ...
Callback’и: Библиотека async 
async.parallel([ 
function(callback){ request('http://google.com/api', 
function(error, response, body) { callback(error, body); }); 
}, 
function(callback){ request('http://yandex.com/api', 
function(error, response, body) { callback(error, body); }); 
}, 
function(callback){ request('http://twitter.com/api', 
function(error, response, body) { callback(error, body); }); 
}, 
], function(err, results) { 
... 
});
Callback’и: Библиотека async 
async.parallel([ 
function(callback){ googleApiService(callback); }, 
function(callback){ yandexApiService(callback); }, 
function(callback){ twitterApiService(callback); }, 
], function(err, results) { 
... 
});
Callback’и: Promise (Q) 
https://github.com/kriskowal/q 
Promise.then(function(success) { 
... 
}, function(error) { 
... 
});
Callback’и: Promise (Q) 
Q.fcall(googleApiService) 
.then(yandexApiService) 
.then(twitterApiService); 
Q.all([ 
googleApiService(), 
yandexApiService(), 
twitterApiService() 
]) 
.then();
Express 
Простой, нетребовательный и 
минималистический middleware- 
фреймворк для разработки WEB- 
приложений на NodeJS; 
$ npm install express --save
Простое приложение на express 
var express = require(“express”), 
app = express(); 
app.get(“/”, function (request, response) { 
response.send(“Hello, stranger!”); 
}); 
app.listen(80);
Приложение на express 
var express = require(“express”), 
app = express(), 
storage = { “home”: { head: “Sweet home” }, “about”: { head: “” } }; 
app.use(express.static(__dirname + “/public”)); 
app.get(“/:page?”, function (request, response) { 
var page = request.params.page, 
data = storage[page || “home”]; 
if (!data) return response.redirect(“/”); 
response.render(“home”, data); 
}); 
app.listen(80);
Элегантность express 
var express = require('express'); 
var path = require('path'); 
var favicon = require('serve-favicon'); 
var logger = require('morgan'); 
var cookieParser = require('cookie-parser'); 
var bodyParser = require('body-parser'); 
var routes = require('./routes/index'); 
var users = require('./routes/users'); 
var app = express(); 
// view engine setup 
app.set('views', path.join(__dirname, 'views')); 
app.set('view engine', 'jade'); 
// uncomment after placing your favicon in /public 
//app.use(favicon(__dirname + '/public/favicon.ico')); 
app.use(logger('dev')); 
app.use(bodyParser.json()); 
app.use(bodyParser.urlencoded()); 
app.use(cookieParser()); 
app.use(express.static(path.join(__dirname, 'public'))); 
app.use('/', routes); 
app.use('/users', users); 
/// catch 404 and forwarding to error handler 
app.use(function(req, res, next) { 
var err = new Error('Not Found'); 
err.status = 404; 
next(err); 
}); 
/// error handlers 
// development error handler 
// will print stacktrace 
if (app.get('env') === 'development') { 
app.use(function(err, req, res, next) { 
res.status(err.status || 500); 
res.render('error', { 
message: err.message, 
error: err 
}); 
}); 
} 
// production error handler 
// no stacktraces leaked to user 
app.use(function(err, req, res, next) { 
res.status(err.status || 500); 
res.render('error', { 
message: err.message, 
error: {} 
}); 
}); 
app.use('/', routes); 
app.use('/users', users); 
module.exports = app;
Сборка проектов 
• Для чего собирать проекты; 
• Система сборки grunt; 
• Gruntfile; 
• Пакеты npm grunt-contrib-*.
Пример Gruntfile.js 
module.exports = function(grunt) { 
grunt.initConfig({ 
uglify: { 
dist: { 
files: { 
“build/app.js”: [“source/app.js”] 
} 
} 
} 
}); 
grunt.loadNpmTasks(“grunt-contrib-uglify”); 
grunt.registerTask(“default”, [“uglify”]); 
}
Node.js введение в технологию, КПИ  #ITmeetingKPI
Grunt устанавливается как NPM 
(Node Package Manager) модуль. 
> npm install -g grunt 
> grunt 
> grunt serve 
> grunt build
Gruntfile.js 
module.exports = function (grunt) { 
require('load-grunt-tasks')(grunt); 
var yeoman = { 
app: 'app' 
}; 
try { 
yeomanConfig.app = 
require('./bower.json').appPath || yeoman.app; 
} catch () {e} 
grunt.initConfig({ 
yeoman: yeomanConfig,
Grunt register tasks - default 
grunt.registerTask 
('default', [ 
'jshint', 
'test', 
'build' 
]);
Grunt register tasks - test 
grunt.registerTask('test', 
[ 
'clean:server', 
'less:modulesToTmp', 
'copy:viewsModulesToTmp', 
'copy:jsModulesToTmp', 
'concat:modulesToTmp', 
'autoprefixer', 
'connect:test', 
'karma' 
]);
Grunt register tasks - build 
grunt.registerTask('build', [ 
'clean:dist', 
'less:modulesToTmp', 
'copy:viewsModulesToTmp', 
'copy:jsModulesToTmp', 
'useminPrepare', 
'autoprefixer', 
'copy:dist', 
'concat', 
'ngmin', 
'uglify', 
'imagemin', 
'htmlmin', 
'usemin', 
'rev'
Grunt register tasks - server 
grunt.registerTask('server', function (target) { 
if (target === 'dist') { 
return grunt.task.run(['build', 'open', 
'connect:dist:keepalive']); 
} 
grunt.task.run([ 
'clean:server', 
'less:modulesToTmp', 
'copy:viewsModulesToTmp', 
'copy:jsModulesToTmp', 
'concat:modulesToTmp', 
'autoprefixer', 
'configureProxies', 
'connect:livereload', 
'open', 
'watch'
Grunt tasks - clean 
clean: { 
server: '<%= yeoman.temp %>', 
dist: { 
files: [{ 
dot: true, 
src: [ 
'<%= yeoman.temp %>', 
'<%= yeoman.dist %>' 
] 
}] 
} 
}
Grunt tasks - less 
less: { 
modulesToTmp: { 
src: '<%= yeoman.app %>/modules/**/*.less', 
dest: '<%= yeoman.temp %>/css/main.css' 
} 
}
Grunt tasks - copy 
copy: { 
viewsModulesToTmp: { 
files: [{ 
expand: true, 
cwd: '<%= yeoman.app %>/modules/', 
dest: '<%= yeoman.temp %>/views', 
src: ['**/*.html'], 
rename: function(dest, src) { 
return dest + '/' + src.replace(/views//gi, ''); 
} 
}]
Grunt tasks - concat 
concat: { 
modulesToTmp: { 
options: { 
banner: '"use strict";n', 
process: function(src, filepath) { 
return '// Source: ' + filepath + 'n' + 
src.replace(/(^|n)[ t]*('use strict'|"use strict");?s*/g, '$1'); 
} 
}, 
files: { 
'<%= yeoman.temp %>/js/controllers.min.js' : '<%= yeoman.app %>/modules/**/*.Controllers.js', 
'<%= yeoman.temp %>/js/directives.min.js' : '<%= yeoman.app %>/modules/**/*.Directives.js', 
'<%= yeoman.temp %>/js/filters.min.js' : '<%= yeoman.app %>/modules/**/*.Filters.js', 
'<%= yeoman.temp %>/js/services.min.js' : '<%= yeoman.app %>/modules/**/*.Services.js' }}}
Grunt tasks - conect 
var LIVERELOAD_PORT = 35729; 
var lrSnippet = require('connect-livereload')({ port: LIVERELOAD_PORT }); 
var proxySnippet = require('grunt-connect-proxy/lib/utils').proxyRequest; 
var mountFolder = function (connect, dir) { return 
connect.static(require('path').resolve(dir)); }; 
connect: { 
options: { port: 8800, hostname: 'localhost' }, 
proxies: [{ context: '/api', host: '127.0.0.1', port: 7777, https: 
false, changeOrigin: false, xforward: false }], 
livereload: { 
options: { 
middleware: function (connect) { 
return [ 
lrSnippet, 
proxySnippet, 
mountFolder(connect, '.tmp'), 
mountFolder(connect, yeomanConfig.app) 
]; }}}
Grunt tasks - open 
open: { 
server: { 
url: 'http://localhost:<%= connect.options.port %>' 
} 
}
Grunt tasks - watch 
watch: { 
livereload: { 
options: { 
livereload: LIVERELOAD_PORT}, 
files: [ 
'<%= yeoman.temp %>/**/*.html', 
'<%= yeoman.temp %>/css/**/*.css', 
'<%= yeoman.temp %>/js/**/*.js', 
'<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}']}, 
js: { 
files: ['<%= yeoman.app %>/modules/**/*.js'], 
tasks: ['copy:jsModulesToTmp', 'concat:modulesToTmp'] 
}, 
css: { 
files: ['<%= yeoman.app %>/modules/**/*.less'], 
tasks: ['less:modulesToTmp']}
Node.js введение в технологию, КПИ  #ITmeetingKPI
Node.js введение в технологию, КПИ  #ITmeetingKPI
Node.js введение в технологию, КПИ  #ITmeetingKPI
Примеры внедрения 
и Highload-проекты
Интерактивное телевидение 7Sense 
• 10млн. открытых соединений на 15 серверах 
• 30тыс. request/second на одном сервере 
• Impress Application Server 
• Server-Sent Events 
• IPC, ZeroMQ
Масштабирование Impress App Server 
Load Balancer 
С1 С3 
C1N1 C1N2 C1N3 C2N1 C2N2 C2N3 C3N1 C3N2 
С0 
Impress Cloud Controller 
Impress 
Application 
Server 
IPC 
HTTP 
ØMQ 
pub/sub + req/rep 
С2 
C3N3
Жизненный цикл проекта 
• Юниттесты и интеграционные тесты 
• Continuous Integration (CI) 
• Travis-CI 
• drone.io 
• Развертывание среды 
• vagrant 
• docker
Сферы применения node.js 
Часто применяется для: 
• cервера веб-приложений и SPA 
• сервера мобильных приложений 
• системы сборки для фронт-энда 
• чаты, меседжинг 
• игровые сервера 
• как заплатка к ПО на других технологиях 
• парсеры, кравлеры
Сферы применения node.js 
Реже применяется для: 
• оконные приложения: node-webkit 
• приложения баз данных и корпоративные 
• промышленная автоматизация и программирование 
микроконтроллеров (arduino, espruino, tessel) 
• обработка и трансляция видео и звука
Сферы применения node.js 
Редко применяется (но подходит) для: 
• CMS, публикация контента 
• электронная коммерция и торговля 
И плохо подходит: 
• вычисления и моделирование 
• научные приложения
Тестирование. TDD.
karma: { 
unit: { 
configFile: 'karma.conf.js', 
singleRun: true 
} 
},
describe('Service: Auth', function () { 
// load the service's module 
beforeEach(module('devApp')); 
// instantiate service 
var Auth; 
beforeEach(inject(function (_Auth_) { 
Auth = _Auth_; 
})); 
it('should do something', function () { 
expect(!!Auth).toBe(true); 
}); 
});
var should = require('should'); 
var request = require('supertest'); 
describe('GET /api/things', function() { 
it('should respond with JSON array', 
function(done) { 
request(app) 
.get('/api/things') 
.expect(200) 
.expect('Content-Type', /json/) 
.end(function(err, res) { 
if (err) return done(err); 
res.body.should.be.instanceof(Array); 
done(); 
});
Node.js введение в технологию, КПИ  #ITmeetingKPI
Полезные материалы 
• npm (www.npmjs.org); 
• nodejs.org/api; 
• learn.javascript.ru; 
• learn.javascript.ru/nodejs-screencast; 
• nodeschool.io; 
• habrahabr.ru/hub/nodejs; 
• nodeguide.ru; 
• …

More Related Content

Node.js введение в технологию, КПИ #ITmeetingKPI

  • 2. От JavaScript никуда не деться «Всё, что может быть написано на JavaScript, должно быть написано на нём» «Any application that can be written in JavaScript, will eventually be written in JavaScript» Jeff Atwood основатель Stack Overflow
  • 3. Основные идеи Node.js 1. Один язык, один формат данных, одна парадигма, одна архитектура СУБД Мобильные приложения Сервер Браузер Оконные приложения JSON BSON JavaScript JavaScript JavaScript
  • 4. Основные идеи Node.js 2. Долгая жизнь приложений в оперативной памяти на стороне сервера • Состояние памяти сохраняется между запросами • Структуры данных (объекты, модель) • Соединения с БД и открытые файлы • Конфигурация и инициализация • Веб сервер внутри приложения, а не наоборот • Меньше IPC
  • 5. Основные идеи Node.js 3. Без ввода/вывода еще быстрее, чем с асинхронным вводом/выводом • Упреждающее чтение • Отложенная запись • Отдача всего из памяти
  • 6. Преимущества JavaScript: 1. Имеет очень низкий порог входа; 2. Высочайшая гибкость; 3. Высокая скорость разработки; 4. Практически идеальный уровень абстракции; …
  • 7. Недостатки JavaScript: 1. Имеет очень низкий порог входа; 2. Высочайшая гибкость; 3. Высокая скорость разработки; 4. Практически идеальный уровень абстракции; …
  • 8. Особенности JavaScript Наличие огромного количества особенностей. Как в синтаксических конструкциях, так и в логике программ. “12” + 5 === “125” Но… “12” - 5 === 7 [] + [] === “” [] + {} === “[object Object]” {} + [] === 0 isNaN({} + {}) === true
  • 10. Что такое NodeJS • Open Source JavaScript-движок V8 от Google; • Обёртка и библиотеки на JavaScript; • libuv; • Оболочка, написанная на C++.
  • 11. Google V8 • Разработка Google, исходный код которой был открыт в 2008 году; • Самый оптимальный JavaScript-движок на сегодняшний день; • Основа браузеров Google Chrome и Chromium.
  • 12. Преимущества V8 • Базовый и оптимизирующий компилятор; • Компиляция JavaScript-кода непосредственно в машинный код, без промежуточного байт-кода; • Эффективная система управления памятью; • Введение скрытых классов и встроенных кэшей, ускоряющих доступ к свойствам и вызовы функций.
  • 13. Начало работы с NodeJS 1. Установка дистрибутива с nodejs.org; 2. Создание *.js файлов; 3. Запуск программ: $ node *.js;
  • 14. Элементарный пример hello.js: console.log(“Hello, world!”); $ node hello Hello, world!
  • 15. API, менеджер пакетов и package.json $ npm init … $ npm install colors --save / /node_modules /colors ... main.js package.json net https buffer crypto path …
  • 16. package.json { "name": "Test", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo "Error: no test specified" && exit 1“ }, "author": "", "license": "ISC" }
  • 17. Система контроля версий • Git; • GitHub; • Структура проектов; • Репозитории npm; • Командная работа.
  • 19. Однопоточность и многопоточность • Что дает однопоточность? • Действительно ли 1 процесс = 1 поток? • Как нагрузить все ядра? • cluster = require('cluster') • npm install webworker-threads • самостоятельно делаем IPC
  • 20. Межпроцессовое взаимодействие • Родное IPC, cluster • Разделяемая память: Memcache? • Шина сообщений (MQ): ZeroMQ, RabbitMQ... • TCP, UDP, HTTP
  • 21. Асинхронный ввод/вывод • Реактор • Очередь • СМО fs.readFile( ‘a.txt’, onRead ); http.get( ‘http://...’, onGet ); console.log(‘done?’);
  • 22. Производительность • Производительность кода • Производительность сервера Факторы производительности Node.js • Асинхронность • Состояние в памяти • Минимизация IPC
  • 23. Память • GC (RAM 32bit: 512Mb, 64bit:1.7Gb ) • node --max-old-space-size=3000 • delete obj.field; delete arr[5]; delete name; • node --nouse-idle-notification --expose-gc application.js • Вызываем gc();
  • 24. Профилирование • npm install -g node-inspector node --debug application.js • npm install heapdump var hd = require('heapdump'); hd.writeSnapshot( 'dump'+Date.now()+'.heapsnapshot' );
  • 25. Отладка • Через node-inspector • Выводом в консоль console.log(); или в лог • Если ошибку не видно • node --stack-trace-limit=1000 application.js • Может понадобиться фильтр
  • 26. Ошибки • Общепринято в Node: function(err, arguments...) • Создаем new Error('Eror message') • Секция try {...} catch(e) {...} finally {...} • Событие .on('error', fn) если EventEmitter • Домены domain.create(); .run(fn); .on('error', fn); • Перехват process.on('uncaughtException', function(err) { console.log('uncaught Exception: '+err.stack); });
  • 27. Обновление кода и перезапуск • Наблюдение за процессом forever npm install forever -g forever start --spinSleepTime 10000 application.js • Наблюдение за файлами http://livereload.com/ http://habrahabr.ru/post/168091/
  • 28. Callback’и и вложенность Пример запроса: request('http://www.google.com/api', function (error, response, body) { var googleData = JSON.parse(body); ... } );
  • 29. Callback’и и вложенность request('http://www.google.com/api', function (gError, gResponse, gBody) { request('http://www.yandex.com/api', function (yError, yResponse, yBody) { request('http://www.twitter.com/api', function (tError, tResponse, tBody) { ... } ...
  • 30. Callback’и: Библиотека async async.parallel([ function(){ ... }, function(){ ... } ], callback); Другие методы: series, parallel, whilst, until, waterfall, compose, queue, cargo, retry, each, map, reduce, detect, every ...
  • 31. Callback’и: Библиотека async async.parallel([ function(callback){ request('http://google.com/api', function(error, response, body) { callback(error, body); }); }, function(callback){ request('http://yandex.com/api', function(error, response, body) { callback(error, body); }); }, function(callback){ request('http://twitter.com/api', function(error, response, body) { callback(error, body); }); }, ], function(err, results) { ... });
  • 32. Callback’и: Библиотека async async.parallel([ function(callback){ googleApiService(callback); }, function(callback){ yandexApiService(callback); }, function(callback){ twitterApiService(callback); }, ], function(err, results) { ... });
  • 33. Callback’и: Promise (Q) https://github.com/kriskowal/q Promise.then(function(success) { ... }, function(error) { ... });
  • 34. Callback’и: Promise (Q) Q.fcall(googleApiService) .then(yandexApiService) .then(twitterApiService); Q.all([ googleApiService(), yandexApiService(), twitterApiService() ]) .then();
  • 35. Express Простой, нетребовательный и минималистический middleware- фреймворк для разработки WEB- приложений на NodeJS; $ npm install express --save
  • 36. Простое приложение на express var express = require(“express”), app = express(); app.get(“/”, function (request, response) { response.send(“Hello, stranger!”); }); app.listen(80);
  • 37. Приложение на express var express = require(“express”), app = express(), storage = { “home”: { head: “Sweet home” }, “about”: { head: “” } }; app.use(express.static(__dirname + “/public”)); app.get(“/:page?”, function (request, response) { var page = request.params.page, data = storage[page || “home”]; if (!data) return response.redirect(“/”); response.render(“home”, data); }); app.listen(80);
  • 38. Элегантность express var express = require('express'); var path = require('path'); var favicon = require('serve-favicon'); var logger = require('morgan'); var cookieParser = require('cookie-parser'); var bodyParser = require('body-parser'); var routes = require('./routes/index'); var users = require('./routes/users'); var app = express(); // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'jade'); // uncomment after placing your favicon in /public //app.use(favicon(__dirname + '/public/favicon.ico')); app.use(logger('dev')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded()); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); app.use('/', routes); app.use('/users', users); /// catch 404 and forwarding to error handler app.use(function(req, res, next) { var err = new Error('Not Found'); err.status = 404; next(err); }); /// error handlers // development error handler // will print stacktrace if (app.get('env') === 'development') { app.use(function(err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: err }); }); } // production error handler // no stacktraces leaked to user app.use(function(err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: {} }); }); app.use('/', routes); app.use('/users', users); module.exports = app;
  • 39. Сборка проектов • Для чего собирать проекты; • Система сборки grunt; • Gruntfile; • Пакеты npm grunt-contrib-*.
  • 40. Пример Gruntfile.js module.exports = function(grunt) { grunt.initConfig({ uglify: { dist: { files: { “build/app.js”: [“source/app.js”] } } } }); grunt.loadNpmTasks(“grunt-contrib-uglify”); grunt.registerTask(“default”, [“uglify”]); }
  • 42. Grunt устанавливается как NPM (Node Package Manager) модуль. > npm install -g grunt > grunt > grunt serve > grunt build
  • 43. Gruntfile.js module.exports = function (grunt) { require('load-grunt-tasks')(grunt); var yeoman = { app: 'app' }; try { yeomanConfig.app = require('./bower.json').appPath || yeoman.app; } catch () {e} grunt.initConfig({ yeoman: yeomanConfig,
  • 44. Grunt register tasks - default grunt.registerTask ('default', [ 'jshint', 'test', 'build' ]);
  • 45. Grunt register tasks - test grunt.registerTask('test', [ 'clean:server', 'less:modulesToTmp', 'copy:viewsModulesToTmp', 'copy:jsModulesToTmp', 'concat:modulesToTmp', 'autoprefixer', 'connect:test', 'karma' ]);
  • 46. Grunt register tasks - build grunt.registerTask('build', [ 'clean:dist', 'less:modulesToTmp', 'copy:viewsModulesToTmp', 'copy:jsModulesToTmp', 'useminPrepare', 'autoprefixer', 'copy:dist', 'concat', 'ngmin', 'uglify', 'imagemin', 'htmlmin', 'usemin', 'rev'
  • 47. Grunt register tasks - server grunt.registerTask('server', function (target) { if (target === 'dist') { return grunt.task.run(['build', 'open', 'connect:dist:keepalive']); } grunt.task.run([ 'clean:server', 'less:modulesToTmp', 'copy:viewsModulesToTmp', 'copy:jsModulesToTmp', 'concat:modulesToTmp', 'autoprefixer', 'configureProxies', 'connect:livereload', 'open', 'watch'
  • 48. Grunt tasks - clean clean: { server: '<%= yeoman.temp %>', dist: { files: [{ dot: true, src: [ '<%= yeoman.temp %>', '<%= yeoman.dist %>' ] }] } }
  • 49. Grunt tasks - less less: { modulesToTmp: { src: '<%= yeoman.app %>/modules/**/*.less', dest: '<%= yeoman.temp %>/css/main.css' } }
  • 50. Grunt tasks - copy copy: { viewsModulesToTmp: { files: [{ expand: true, cwd: '<%= yeoman.app %>/modules/', dest: '<%= yeoman.temp %>/views', src: ['**/*.html'], rename: function(dest, src) { return dest + '/' + src.replace(/views//gi, ''); } }]
  • 51. Grunt tasks - concat concat: { modulesToTmp: { options: { banner: '"use strict";n', process: function(src, filepath) { return '// Source: ' + filepath + 'n' + src.replace(/(^|n)[ t]*('use strict'|"use strict");?s*/g, '$1'); } }, files: { '<%= yeoman.temp %>/js/controllers.min.js' : '<%= yeoman.app %>/modules/**/*.Controllers.js', '<%= yeoman.temp %>/js/directives.min.js' : '<%= yeoman.app %>/modules/**/*.Directives.js', '<%= yeoman.temp %>/js/filters.min.js' : '<%= yeoman.app %>/modules/**/*.Filters.js', '<%= yeoman.temp %>/js/services.min.js' : '<%= yeoman.app %>/modules/**/*.Services.js' }}}
  • 52. Grunt tasks - conect var LIVERELOAD_PORT = 35729; var lrSnippet = require('connect-livereload')({ port: LIVERELOAD_PORT }); var proxySnippet = require('grunt-connect-proxy/lib/utils').proxyRequest; var mountFolder = function (connect, dir) { return connect.static(require('path').resolve(dir)); }; connect: { options: { port: 8800, hostname: 'localhost' }, proxies: [{ context: '/api', host: '127.0.0.1', port: 7777, https: false, changeOrigin: false, xforward: false }], livereload: { options: { middleware: function (connect) { return [ lrSnippet, proxySnippet, mountFolder(connect, '.tmp'), mountFolder(connect, yeomanConfig.app) ]; }}}
  • 53. Grunt tasks - open open: { server: { url: 'http://localhost:<%= connect.options.port %>' } }
  • 54. Grunt tasks - watch watch: { livereload: { options: { livereload: LIVERELOAD_PORT}, files: [ '<%= yeoman.temp %>/**/*.html', '<%= yeoman.temp %>/css/**/*.css', '<%= yeoman.temp %>/js/**/*.js', '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}']}, js: { files: ['<%= yeoman.app %>/modules/**/*.js'], tasks: ['copy:jsModulesToTmp', 'concat:modulesToTmp'] }, css: { files: ['<%= yeoman.app %>/modules/**/*.less'], tasks: ['less:modulesToTmp']}
  • 58. Примеры внедрения и Highload-проекты
  • 59. Интерактивное телевидение 7Sense • 10млн. открытых соединений на 15 серверах • 30тыс. request/second на одном сервере • Impress Application Server • Server-Sent Events • IPC, ZeroMQ
  • 60. Масштабирование Impress App Server Load Balancer С1 С3 C1N1 C1N2 C1N3 C2N1 C2N2 C2N3 C3N1 C3N2 С0 Impress Cloud Controller Impress Application Server IPC HTTP ØMQ pub/sub + req/rep С2 C3N3
  • 61. Жизненный цикл проекта • Юниттесты и интеграционные тесты • Continuous Integration (CI) • Travis-CI • drone.io • Развертывание среды • vagrant • docker
  • 62. Сферы применения node.js Часто применяется для: • cервера веб-приложений и SPA • сервера мобильных приложений • системы сборки для фронт-энда • чаты, меседжинг • игровые сервера • как заплатка к ПО на других технологиях • парсеры, кравлеры
  • 63. Сферы применения node.js Реже применяется для: • оконные приложения: node-webkit • приложения баз данных и корпоративные • промышленная автоматизация и программирование микроконтроллеров (arduino, espruino, tessel) • обработка и трансляция видео и звука
  • 64. Сферы применения node.js Редко применяется (но подходит) для: • CMS, публикация контента • электронная коммерция и торговля И плохо подходит: • вычисления и моделирование • научные приложения
  • 66. karma: { unit: { configFile: 'karma.conf.js', singleRun: true } },
  • 67. describe('Service: Auth', function () { // load the service's module beforeEach(module('devApp')); // instantiate service var Auth; beforeEach(inject(function (_Auth_) { Auth = _Auth_; })); it('should do something', function () { expect(!!Auth).toBe(true); }); });
  • 68. var should = require('should'); var request = require('supertest'); describe('GET /api/things', function() { it('should respond with JSON array', function(done) { request(app) .get('/api/things') .expect(200) .expect('Content-Type', /json/) .end(function(err, res) { if (err) return done(err); res.body.should.be.instanceof(Array); done(); });
  • 70. Полезные материалы • npm (www.npmjs.org); • nodejs.org/api; • learn.javascript.ru; • learn.javascript.ru/nodejs-screencast; • nodeschool.io; • habrahabr.ru/hub/nodejs; • nodeguide.ru; • …