146
Node.js 1

Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

  • Upload
    others

  • View
    15

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Node.js

1

Page 2: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Платформа для исполнения программ,написанных на JavaScript

2

Page 3: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Программы можно разделить по степенипотребления разных ресурсов –

CPU, mem, I/O

3

Page 4: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Это определяется набором операцийпрограммы, зависимых от тех или иных

видов ресурсов (bound)

4

Page 5: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Вычисление числа Фибоначчи – CPU bound,подсчёт строк в файле – I/O bound

5

Page 6: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Операции в web-приложении

Чтение HTTP запроса I/O

Парсинг HTTP запроса CPU

Запрос к базе данных I/O

Запрос к API I/O

Генерация HTML CPU

Отправка HTML I/O6

Page 7: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Поток выполнения

Idle

cpu

cpu

i/o

7

Page 8: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

В одном потоке одновременно выполняетсятолько одна операция

8

Page 9: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Один поток, один пользовательApp OS

User 1

9

Page 10: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Изначально I/O-операции былиблокирующими

Управление передаётся ОС и возвращаетсяприложению только после того, как ОС

закончит чтение или запись данных

10

Page 11: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Один поток, несколько пользователейApp OS

User 1

User 2

11

Page 12: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Блокирующее I/O нерационально расходуетресурс CPU

12

Page 13: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Ресурс CPU – очень дорогой

13

Page 14: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Чтение 1 Кб данных c SSD – 28 000 циклов наодном 2Ghz ядре

1 cетевое соединение – 132 000 000 цикловна одном 2Ghz ядре

14

Page 15: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

C ростом числа одновременныхпользователей блокирующее I/O тормозит

обработку новых запросов

15

Page 16: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

MultithreadingApp OS App

16

Page 17: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Multithreading

Поднятие потока – дорогая операция, нообычно используется пулл уже поднятых

Ограничение на количество

Каждый поток – дополнительная память

17

Page 18: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Non-blocking I/OApp OS

18

Page 19: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Синхронное выполнение операцииtry { const data = readFileSync('data.json'); console.log(data); } catch(err) { console.error(err); }

19

Page 20: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Асинхронное выполнение операцииreadFileAsync('data.json', (err, data) => { if (err) { console.error(err); } console.log(data); });

20

Page 21: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Event &Callback

Event &Callback

Event Queue

EventLoop

Application

Callback Вызывает callbackпо ссылке

Кладёт событие

Забираетсамое старое

событие

21

Page 22: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Thread

Event loop

Application

Event loop

Application

Event loop

Application

22

Page 23: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Event &Callback

Event &Callback

Event Queue

EventLoop

Application

Callback Вызывает callbackпо ссылке

Кладёт событие

Забираетсамое старое

событие

Read file &Callback

&Callback

Event Demultiplexer

Get url

ЗапрашиваетI/O ресурс

Возвращаетуправление

Как только ресурс готов, кладётсобытие

23

Page 24: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Thread

Event loop

Application

Event Demultiplexer

Event loop

Application

Application

Если опустелаEvent Queue

24

Page 25: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Такой подход заключили в паттерн Reactor

25

Page 26: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Apache vs Nginx

26

Page 27: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Apache vs Nginx

27

Page 28: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Timers

I/O Callbacks

I/O Polling

Immediates

Close callbacks

28

Page 29: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Node.js последовательно проходит фазы вкаждом цикле

29

Page 30: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

К каждой фазе привязана отдельнаяочередь событий

30

Page 31: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Timers

I/O Callbacks

I/O Polling

Immediates

Close callbacks

31

Page 32: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Timers – фаза, в которой последовательновызываются обработчики истёкших

таймеров

32

Page 33: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

setTimeout(handler, 2000); setInterval(handler, 2000);

33

Page 34: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Timers

I/O Callbacks

I/O Polling

Immediates

Close callbacks

34

Page 35: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

I/O Callback – фаза, в которойпоследовательно вызываются обработчики

выполненных асинхронных операций

35

Page 36: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

fs.readFile(path, handler);

36

Page 37: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Timers

I/O Callbacks

I/O Polling

Immediates

Close callbacks

37

Page 38: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

I/O polling – фаза, в которой происходитожидание завершения I/O операций

Event Demultiplexer

38

Page 39: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

I/O polling происходит, если нет событий в других очередях

39

Page 40: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Время допустимое для I/O pollingрасчитывается

как время до ближайшего таймера

40

Page 41: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Timers

I/O Callbacks

I/O Polling

Immediates

Close callbacks

41

Page 42: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Immediates – фаза, в которойпоследовательно вызываются обработчики

созданные setImmediate

42

Page 43: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

setImmediate(handler);

43

Page 44: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Timers

I/O Callbacks

I/O Polling

Immediates

Close callbacks

44

Page 45: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Close callbacks – фаза, в которойпоследовательно вызываются обработчики

связанные c закрытием I/O процесса

45

Page 46: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

socket.on('close', handler)

46

Page 47: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Timers

I/O Callbacks

I/O Polling

Immediates

Close callbacks

Microtasks

Microtasks

Microtasks

Microtasks

47

Page 48: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Очередь микрозадач разбирается междукаждой фазой пока не опустеет

48

Page 49: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

В ходе разбора очереди микрозадач, онаможет полнять себя бесконечно

49

Page 50: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Цель микрозадач – уменьшать задержкумежду исполняемыми участками кода

50

Page 51: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

NextTicks

Promises Callbacks

51

Page 52: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

process.nextTick(handler)

52

Page 53: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Promise.resolve(handler)

53

Page 54: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

В 2009 Ryan Dahl cоздаёт Node.js

54

Page 55: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

В разных операционных системах Eventnotification interface реализован по разному

I/O Completion Port API в windows,epoll в linux, kqueue в osx

55

Page 56: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Библиотека libuv скрывает разнуюреализацию за единым интерфейсом

56

Page 57: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

libuv так же включает в себя реализациюEvent Demultiplexer, Event Queue и Event Loop

57

Page 58: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Особенности libuv

В linux операции над локальнымифайлами всегда блокирующие (в отличиеот сетевых операций)

Для эмуляции неблокирующегоповедения libuv использует потоки

По умолчанию создаётся пулл 4 потоков58

Page 59: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Почитать про libuv

Bert Belder

docs.libuv.org

docs.libuv.org

About libuv

Design overview

Basics of libuv

59

Page 60: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

v8

libuv

Core API

60

Page 61: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

JavaScript и v8

и замыкания

Готов к EventLoop (DOM events, setTimeout)

Отсутствие багажа в виде синхронныхбиблиотек (как у Lua, например)

Быстрый интерпретатор v8

Функции первого класса

61

Page 62: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Core API

API для работы с файловой системой, дляобщения по http, логирования и другие

62

Page 63: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Почитать про Node.js

Ryan Dahl

Deepal Jayasekara

Eugene Obrezkov

Original Node.js presentation

Event Loop and the Big Picture

How does NodeJS work

63

Page 64: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Getting started

64

Page 65: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Для установки Node.js рекомендуетсяиспользовать

Позволяет одновременно установитьнесколько разных версий Node.js

Node Version Manager

65

Page 66: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Установка на Windows

Установка на osx/nix

66

Page 67: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Node Version Manager

$ nvm use 9Now using node v9.2.0 (npm v5.5.1)

$ nvm ls v8.9.1 -> v9.2.0

$ nvm install 9Downloading and installing node v9.2.0... Downloading https://nodejs.org/dist/v9.2.0/node-v9.2.0-darwin-x###############################################################Computing checksum with sha256sum Checksums matched!

67

Page 68: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Node$ node -v v9.2.0

$ node -p '2 + 2'4

$ node -h Usage: node [options] [ -e script | script.js | - ] [arguments] node inspect script.js [arguments] Options: -v, --version print Node.js version

68

Page 69: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

REPL$ node > 2 + 24 > .help .break Sometimes you get stuck, this gets you out .clear Alias for .break .editor Enter editor mode .exit Exit the repl .help Print this help message .load Load JS from a file into the REPL session .save Save all evaluated commands to a file

69

Page 70: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

REPL$ node > .editor // Entering editor mode (^D to finish, ^C to cancel)let a = 2; a * 2;

4 >

70

Page 71: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Модули

71

Page 72: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Чтобы упростить разработку итестирование приложения – код разделяют

на небольшие изолированные модули

72

Page 73: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Модуль для платформы Node.js – отдельныйфайл с кодом на JavaScript

73

Page 74: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Node.js добавляет возможностьэкпортировать функциональность из

одного модуля и импортировать её в другом

74

Page 75: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Возможности импорта и экспорта описаныспецификацией Modules/1.1.1

75

Page 76: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Спецификация разрабатывается группой, которая пытается

стандартизировать различные APICommonJS

76

Page 77: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Модуль// file: index.js function sum(nums) { return nums.reduce((acc, num) => acc + num); } function average(...nums) { return sum(nums) / nums.length; } average(1, 2, 3); // 2

77

Page 78: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Экспорт из модуля// file: average.js function sum(nums) { return nums.reduce((acc, num) => acc + num); } module.exports = function average(...nums) { return sum(nums) / nums.length; }

78

Page 79: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Node.js для каждого модуля делаетдоступным объект module, который

описывает модуль

79

Page 80: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Из модуля экпортируется значениепомещённое в поле module.exports

Это может быть функция, конструктор,объект, число, «класс» – что угодно

80

Page 81: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

По умолчанию exports хранит пустой объект

81

Page 82: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Импорт модуля// file: index.js const average = require('./average'); average(1, 2, 3); // 2

82

Page 83: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Node.js содержит встроенные модули

Например, fs для работы с файламиили util со вспомогательными утилитами

Мы можем их импортировать в свои модули

83

Page 84: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Импорт встроенного модуля// file: index.js const { format } = require('util'); const average = require('./average'); format('Average is %d', average(1, 2, 3)); // Average is 2

84

Page 85: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Node.js поддерживает импорт из файловразных типов – json, js, mjs.

85

Page 86: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Импорт JSON// file: data.json { "year": 1703 } // file: index.js const data = require('./data.json'); console.log(data); // { year: 1703 }

86

Page 87: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Существенная часть кода Node.jsнаписана на JavaScript

Код модульной системы описан в файле на GitHub/lib/module.js

87

Page 88: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Модули изнутриfunction require(path) { return Module._load(path); } function Module() { this.exports = {}; this.filename = null; }

88

Page 89: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Модули изнутриModule._load = function(path) { var filename = Module._resolveFilename(path); var module = new Module(); module.load(filename); return module.exports; } Module._resolveFilename = function(path) { // ./average -> /Users/gogoleff/lecture/average.js }

89

Page 90: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Модули изнутриconst path = require('path'); Module.prototype.load = function(filename) { this.filename = filename; var extension = path.extname(filename) || '.js'; Module._extensions[extension](this, filename); }; Module._extensions['.js'] = function (module, filename) {}; Module._extensions['.mjs'] = function (module, filename) {}; Module._extensions['.json'] = function (module, filename) {};

90

Page 91: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Модули изнутриconst fs = require('fs'); Module._extensions['.json'] = function(module, filename) { var content = fs.readFileSync(filename, 'utf8'); module.exports = JSON.parse(content); };

91

Page 92: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Модули изнутриconst json = require('./data.json'); function require(path) { return Module._load(path);

} Module._load = function(path) { // ... получаем полный путь до файла module.load(filename); return module.exports; } Module.prototype.load = function(filename) { // ... узнаём расширение файла Module._extensions[extension](this, filename); }; Module._extensions['.json'] = function(module, filename) { var content = fs.readFileSync(filename, 'utf8'); module.exports = JSON.parse(content); }; 92

Page 93: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Модули изнутриModule._extensions['.js'] = function(module, filename) { var content = fs.readFileSync(filename, 'utf8'); module._compile(content, filename); };

93

Page 94: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Модули изнутриconst vm = require('vm'); // Для интерпретации кода в v8 Module.prototype._compile = function(content, filename) { var wrapper = Module.wrap(content);

// (function (exports, require, module, __filename, __dirname) {', // module.exports.average = function () {} // }); var compiledWrapper = vm.runInThisContext(wrapper); // Похоже на eval var dirname = path.dirname(filename); compiledWrapper.call( this.exports, // -> this – ссылка на module.exports this.exports, // -> exports – ссылка на module.exports require, // -> require this, // -> module filename, // -> __filename – файл модуля dirname // -> __dirname – директория модуля ); };

94

Page 95: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Модуль// file: index.js console.log(module.filename); // /Users/gogoleff/lecture/index.js console.log(__filename); // /Users/gogoleff/lecture/index.js console.log(this === module.exports); // true console.log(exports === module.exports); // true

95

Page 96: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Экпорт из модуля// file: average.js function sum(nums) {} module.exports.average = function(...nums) {}

// Можно так exports.average = function(...nums) {} // Или такthis.average = function(...nums) {}

// Но не так! exports = function(...nums) {}

96

Page 97: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Кеширование импорта// file: counter.js let counter = 1; module.exports = () => counter++; // file: index.js var counter = require('./counter'); var anotherCounter = require('./counter'); Возьмёт из кеша console.log(counter()); // 1console.log(counter()); // 2console.log(anotherCounter()); // 3

97

Page 98: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Модули изнутриModule._cache = Object.create(null); Module._load = function(path) {

var filename = Module._resolveFilename(path); if (Module._cache[filename]) return Module._cache[filename].exports; var module = new Module(); Module._cache[filename] = module; module.load(filename); return module.exports; }

98

Page 99: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Модули импортируются один раз и затемкешируются по абсолютному пути до файла

Кэш можно посмотреть в поле require.cache

99

Page 100: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Кеширование импорта// file: index.js const average = require('./average'); console.log(require.cache); // {// '/Users/gogoleff/lecture/average.js': Module {// exports: { average: [Function: average] },// filename: '/Users/gogoleff/Downloads/average.js'// }

// А так можно очистить кешdelete require.cache[path.resolve('./average.js')];

100

Page 101: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Модуль, c которого начинаетсяинтерпретация, называется главным

Ссылка на него хранится в поле require.main

101

Page 102: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Главный модуль// file: average.js const isMain = require.main === module; // false // file: index.js const average = require('./average'); const isMain = require.main === module; // true

$ node index.js

102

Page 103: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

CLI

103

Page 104: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Параметры командной строки$ node index.js --name=sergey

console.log(process.argv); // [ '/Users/gogoleff/.nvm/versions/node/v9.2.0/bin/node',// '/Users/gogoleff/lecture/index.js',// '--name=sergey' ]

104

Page 105: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Параметры командной строкиconst { argv } = process; const nameArg = argv.find(arg => arg.startsWith('--name=')); const [key, value] = nameArg.slice(2).split('='); console.log(`Hello, ${value}`);

$ node index.js --name=SergeyHello, Sergey

105

Page 106: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Переменные окружения$ node NODE_ENV=production index.js

console.log(process.env.NODE_ENV); // production console.log(process.env); // {// ...// USER: 'gogoleff',// NODE_ENV: 'production'// ...// }

106

Page 107: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Переменные окружения

$ node index.js Hello, gogoleff

const { argv, env } = process; const nameArg = argv.find(arg => arg.startsWith('--name=')) || const [key, value] = nameArg.slice(2).split('='); console.log(`Hello, ${value || env.USER}`);

107

Page 108: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Окружение хранит множество настроек(переменных) в виде пар «ключ=значение»

При создании процесса, он получаетлокальную копию окружения

108

Page 109: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

В windows ключи переменных окружениярегистронезависимы!

109

Page 110: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Переменные окружения$ node NODE_ENV=production index.js

// file: module.js process.env.NODE_ENV = 'development'; // file: index.js require('./module'); console.log(process.env.NODE_ENV); // development

110

Page 111: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

NODE_ENV используется многимибиблиотеками, чтобы определить

окружение, где запускается приложение

111

Page 112: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Node.js использует путь указанный вNODE_PATH для поиска модулей

112

Page 113: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

NODE_PATH// Без указания NODE_PATHrequire('/home/gogoleff/common/module.js');

$ node NODE_PATH=/home/gogoleff/common/ index.js

// С указанием NODE_PATHrequire('module.js');

113

Page 114: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Увеличить количество потоков для работы слокальными файлами можно в переменной

UV_THREADPOOL_SIZE

114

Page 115: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Пользовательский вводconst { createInterface } = require('readline'); const session = createInterface({ input: process.stdin, output: process.stdout }); session.question('What is your name?', name => { rl.write(`Hello, ${name}`); session.close(); });

$ node index.js What is your name? Sergey Hello, Sergey 115

Page 116: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Стандартные потоки ввода/вывода// Эквивалентно console.error process.stderr.write('Some error'); // Эквивалентно console.log process.stdout.write('Information message');

$ node index.js 2>stderr.log 1>stdout.log $ cat stderr.logSome error $ cat stdout.logInformation message

116

Page 117: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Стандартные потоки ввода/выводаprocess.stdin.setEncoding('utf8'); process.stdin.on('readable', () => { const input = process.stdin.read(); if (input) { process.stdout.write(input); } });

$ echo 'User input' | node index.js User input

117

Page 118: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Выход из приложенияprocess.exit(1); // 0 по умолчанию

118

Page 119: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

process.exit убивает процесс максимальнобыстро, не дожидаясь заверешения

асинхронных операций!

119

Page 120: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Веб-приложение

120

Page 121: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Модуль eventsconst EventEmitter = require('events'); const emitter = new EventEmitter(); emitter.on('log', console.info); emitter.emit('log', 'Hello!'); // Hello! emitter.emit('unknown event'); // Do nothing emitter.emit('error'); // Uncaught, unspecified "error" event.

121

Page 122: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Всегда привязывайте обработчик ксобытию error

122

Page 123: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Если к событию привязано более 10обработчиков, Node.js заподозрит неладное

Возможно мы лишний раз привязываемодин и тот же обработчик или не

отвязываем, вызывая утечку памяти

Можно успокоить Node.js увеличивзначение emitter.setMaxListeners(42)

123

Page 124: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

http-серверconst http = require('http'); const server = new http.Server(); server.on('request', (req, res) => { res.end('Hello, Anonymous!'); }); server.listen(8080);

124

Page 125: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

http-серверconst http = require('http'); const { parse: parseUrl } = require('url'); const { parse: parseQuery } = require('querystring'); const server = new http.Server(); server.on('request', (req, res) => { const { query } = parseUrl(req.url); // name=Sergey const { name } = parseQuery(query); // Sergey res.end(`Hello, ${name}!`); }); server.listen(8080);

125

Page 126: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Объект reqserver.on('request', (req, res) => { console.info(req.url); // /?name=Sergey console.info(req.method); // GET console.info(req.headers); // { 'accept-encoding': 'gzip' } });

126

Page 127: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Объект resserver.on('request', (req, res) => { res.setHeader('content-type', 'text/html'); res.write('Hello,'); res.write('<strong>Anonymous</strong>'); res.end('!') });

127

Page 128: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Модуль urlurl.parse('https://yandex.ru/'); // {// protocol: 'https:',// host: 'yandex.ru',// path: '/',// ...// }

url.format({ protocol: 'https:', host: 'yandex.ru' }); // https://yandex.ru/

128

Page 129: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Модуль querystringquerystring.parse('foo=bar&arr=a&arr=b'); // {// foo: 'bar',// arr: ['a', 'b']// }

querystring.stringify({ foo: 'bar', arr: ['a', 'b'] }); // foo=bar&arr=a&arr=b

129

Page 130: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

http-клиентconst http = require('http'); const req = http.request({ hostname: 'localhost', port: 8080 });

130

Page 131: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

http-клиентreq.on('response', response => { let body = ''; response.on('data', chunk => { body += chunk; // res.write(); }); response.on('end', () => { console.info(body); // res.end(); }); });

131

Page 132: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Почитать про модули

nodejs.org

nodejs.org

Exploring.js

Node.js Guides

Node.js API docs

16. Modules

132

Page 133: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

npm

133

Page 134: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Прежде чем написать свой модуль,рассмотрите уже существующие

134

Page 135: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Для того чтобы поделиться своим модулем,из него необходимо сделать пакет

135

Page 136: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Пакет – это модуль плюс файл-манифест

136

Page 137: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Создание файла манифеста$ npm init package name: (average) version: (1.0.0) description: Calculate average number author: Sergey Gogolev license: (ISC) MIT About to write to /Users/gogoleff/lecture/average/package.json { "name": "average", "version": "1.0.0", "description": "Calculate average number", "author": "Sergey Gogolev", "license": "MIT" } 137

Page 138: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

{ "name": "average", "version": "1.0.0", "description": "Calculate average number", "author": "Sergey Gogolev", "license": "MIT" }

package.json

138

Page 139: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Установка зависимостей

const { sum } = require('lodash'); exports.average = (...nums) => sum(nums) / nums.length;

$ npm install lodash npm notice created a lockfile as package-lock.json. You should + [email protected] added 1 package from 2 contributors and audited 1 package in 1.

139

Page 140: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Зависимости устанавливаются вдиректорию node_modules

Функция require ищет в ней модули,если не находит встроенного

140

Page 141: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Зависимости фиксируются в package.json

141

Page 142: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

package.json{ "name": "average", "version": "1.0.0", "description": "Calculate average number", "author": "Sergey Gogolev", "license": "MIT", "dependecies": { "lodash": "4.17.4" } }

142

Page 143: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Пакеты публикуются в реестр npmjs.com

143

Page 144: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

$ cat package-lock.json "name": "average", "version": "1.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { "lodash": { "version": "4.17.4", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.1 "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" } }

package-lock.json

144

Page 145: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

Если есть файл package-lock.json, npmустановит зависимости согласно ему

Если нет, npm установит зависимостисогласно package.json и сгенерирует на его

основе package-lock.json

145

Page 146: Node - urfu-2019.github.io · Это определяется набором операций программы, зависимых от тех или иных видов рес

package-lock.json гарантирует, что у всехразработчиков и на всех серверах будетустановлен идентичный набор пакетов

146