Node.js введение в технологию, КПИ #ITmeetingKPI
-
Upload
timur-shemsedinov -
Category
Engineering
-
view
346 -
download
7
description
Transcript of Node.js введение в технологию, КПИ #ITmeetingKPI
Введение в технологию
От JavaScript никуда не деться
«Всё, что может быть написано на JavaScript, должно быть написано на нём»
«Any application that can be written in JavaScript, will eventually be written in JavaScript»
Jeff Atwood основатель Stack Overflow
Основные идеи Node.js
1. Один язык, один формат данных,одна парадигма, одна архитектура
СУБДМобильныеприложения Сервер
Браузер
Оконныеприложения
HTTP / JSONJSON
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
NaN !== NaNnull === null
[] + [] === “”[] + {} === “[object Object]”{} + [] === 0isNaN({} + {}) === 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;
Элементарный пример
console.log(“Hello, world!”);
hello.js:
$ node helloHello, world!
API, менеджер пакетов и package.json
$ npm init…$ npm install colors --save
/ /node_modules /colors ... main.js package.json
nethttpsbuffercrypto
path…
var ht
tp = r
equire
(“http
”);
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-inspectornode --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);});
Обновление кода и перезапуск
• Наблюдение за процессом forevernpm install forever -gforever 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
$ npm install express --save
Простой, нетребовательный и минималистический middleware-фреймворк для разработки WEB-приложений на NodeJS;
Простое приложение на express
var express = require(“express”), app = express();
app.get(“/”, function (request, response) { response.send(“Hello, stranger!”);});
app.listen(80);
Приложение на expressvar 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);
Элегантность expressvar 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 setupapp.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 handlerapp.use(function(req, res, next) { var err = new Error('Not Found'); err.status = 404; next(err);});
/// error handlers
// development error handler// will print stacktraceif (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 userapp.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.jsmodule.exports = function(grunt) {
grunt.initConfig({ uglify: { dist: { files: { “build/app.js”: [“source/app.js”] } } } });
grunt.loadNpmTasks(“grunt-contrib-uglify”);
grunt.registerTask(“default”, [“uglify”]);
}
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.registerTask('default', [ 'jshint', 'test', 'build' ]);
Grunt register tasks - default
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'
clean: { server: '<%= yeoman.temp %>', dist: { files: [{ dot: true, src: [ '<%= yeoman.temp %>', '<%= yeoman.dist %>' ] }] } }
Grunt tasks - clean
less: { modulesToTmp: { src: '<%= yeoman.app %>/modules/**/*.less', dest: '<%= yeoman.temp %>/css/main.css' } }
Grunt tasks - less
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 - copy
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 - concat
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 - conect
open: { server: { url: 'http://localhost:<%= connect.options.port %>' } }
Grunt tasks - open
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']}
Grunt tasks - watch
Примеры внедренияи Highload-проекты
Интерактивное телевидение 7Sense
• 10млн. открытых соединений на 15 серверах• 30тыс. request/second на одном сервере
• Impress Application Server• Server-Sent Events• IPC, ZeroMQ
Масштабирование Impress App ServerLoad Balancer
С1 С3
С0
C2N2C1N2C1N1 C1N3 C2N1 C2N3 C3N1 C3N2
Impress Cloud Controller
Impress Application Server
IPC
HTTP
ØMQpub/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(); });
Полезные материалы
• npm (www.npmjs.org);• nodejs.org/api;• learn.javascript.ru;• learn.javascript.ru/nodejs-screencast;• nodeschool.io;• habrahabr.ru/hub/nodejs;• nodeguide.ru;• …