HackerX https://hackerx.ru Блог о программировании, СУБД, сетях и алгоритмах. Уроки и статьи по разным языкам программирования Wed, 11 Jul 2018 07:15:23 +0000 ru-RU hourly 1 https://wordpress.org/?v=4.9.8 Сжатие / восстановление данных с использованием библиотеки Zlib https://hackerx.ru/node-data-compression-library-zlib/ https://hackerx.ru/node-data-compression-library-zlib/#respond Sun, 08 Jul 2018 14:15:08 +0000 https://hackerx.ru/?p=999 Модуль Zlib предоставляет функциональность сжатия/восстановления данных. В его основу заложен поток преобразования данных, что становится очевидным после знакомства с примером сжатия файла, приведенным в документации Node. Я слегка изменила этот пример для работы с большим файлом. const zlib = require('zlib'); const fs = require('fs'); const gzip = zlib.createGzip(); const inp = fs.createReadStream('test.png'); var out = […]

The post Сжатие / восстановление данных с использованием библиотеки Zlib appeared first on HackerX.

]]>
Модуль Zlib предоставляет функциональность сжатия/восстановления данных. В его основу заложен поток преобразования данных, что становится очевидным после знакомства с примером сжатия файла, приведенным в документации Node. Я слегка изменила этот пример для работы с большим файлом.

const zlib = require('zlib');
const fs = require('fs');

const gzip = zlib.createGzip();

const inp = fs.createReadStream('test.png');
var out = fs.createWriteStream('test.png.gz');

inp.pipe(gzip).pipe(out);

Входной поток напрямую связывается с выходным, а передаваемые между ними данные подвергаются сжатию gzip, то есть происходит преобразование данных, в данном случае файла PNG.

Zlib предоставляет поддержку сжатия zlib и deflate — более сложного и управляемого алгоритма сжатия. Если файлы, созданные с применением zlib, могут быть распакованы программой командной строки gunzip (или unzip), у файлов, созданных с применением deflate, такая возможность отсутствует. Для восстановления файла, сжатого в режиме deflate, придется использовать Node или другую функциональность.

Чтобы продемонстрировать функциональность сжатия и восстановления файлов, мы создадим две программы командной строки: compress и uncompress.

Первая программа сжимает файл с выбором алгоритма gzip или deflate в параметрах командной строки. Так как мы собираемся работать с параметрами командной строки, для них также следует включить модуль Commander:

const zlib = require('zlib');
const program = require('commander');
const fs = require('fs');

program
  .version ('0.0.1')
  .option ('-s, --source [file name]', 'Source File Name')
  .option ('-f, --file [file name]', 'Destination File name')
  .option ('-t, --type <mode>', /^(gzip|deflate)$/i)
  .parse(process.argv);

var compress;
if (program.type == 'deflate')
  compress = zlib.createDeflate();
else
  compress = zlib.createGzip();

var inp = fs.createReadStream(program.source);
var out = fs.createWriteStream(program.file);

inp.pipe(compress).pipe(out);

Такие приложения интересны и полезны (особенно в среде Windows, в которой нет встроенной реализации сжатия), но технология сжатия особенно популярна в веб-запросах. Документация Node содержит примеры функциональности Zlib с веб-запросами.

Вместо получения сжатых файлов я покажу, как отправить сжатый файл на сервер, где он затем будет восстановлен. Сейчас мы создадим клиент и сервер для сжатия большого файла PNG и отправки его с запросом HTTP. Далее сервер будет восстановить данные и сохраняет файл.



Обратите внимание: передаваемые данные читаются в массив фрагментов, который затем используется для создания нового объекта Buffer вызовом buffer.concat(). Так как мы работаем с буфером, а не с потоком, использовать функцию pipe() не удастся. Вместо этого я буду использовать вспомогательную функцию Zlib zlib.unzip, которой передается объект Buffer и функция обратного вызова. Аргументы функции обратного вызова содержат ошибку и результат. Результат также представляет собой объект Buffer, который записывается во вновь созданный поток для записи функцией write(). Чтобы программа создавала разные экземпляры файла, имя файла дополняется временной меткой.

Создание веб-сервера, который получает сжатые данные и распаковывает их в файл:

const http = require('http');
const zlib = require('zlib');
const fs = require('fs');

const server = http.createServer().listen(8080);

server.on('request', function(request,response) {
  if (request.method == 'POST') {
    var chunks = [];

    request.on('data', function(chunk) {
      chunks.push(chunk);
    });

    request.on('end', function() {
      var buf = Buffer.concat(chunks);
      zlib.unzip(buf, function(err, result) {
        if (err) {
          response.writeHead(500);
          response.end();
          return console.log('error ' + err);
        }
        var timestamp = Date.now();
        var filename = './done' + timestamp + '.png';
        fs.createWriteStream(filename).write(result);
      });
      response.writeHead(200, {'Content-Type': 'text/plain'});
      response.end('Received and undecompressed file\n');
    });
  }
});

console.log('server listening on 8080');

Ключевой момент клиентского кода в листинге — назначение правильной кодировки Content-Encoding в заголовке. Заголовок должен содержать значение ‘gzip,deflate’. Также заголовок Content-Type: ‘application/javascript’.

Клиент сжимает файл и передает его с веб-запросом:

const http = require('http');
const fs = require('fs');
const zlib = require('zlib');
const gzip = zlib.createGzip();

const options = {
  hostname: 'localhost',
  port: 8124,
  method: 'POST',
  headers: {
    'Content-Type': 'application/javascript',
    'Content-Encoding': 'gzip,deflate'
  }
};

const req = http.request(options, function(res) {
  res.setEncoding('utf8');
  var data = '';
  res.on('data', function (chunk) {
    data+=chunk;
  });

  res.on('end', function() {
    console.log(data)
  })
});

req.on('error', function(e) {
  console.log('problem with request: ' + e.message);
});

// Потоковая передача сжатого файла серверу
var readable = fs.createReadStream('./test.png');
readable.pipe(gzip).pipe(req);

Клиент открывает файл для сжатия и передает его в поток преобразования данных, выполняющий сжатие Zlib; результат передается в веб-запрос (который представляет собой поток для записи). В коде мы работаем исключительно с потоками, что позволяет нам использовать функциональность pipe(), которая уже использовалась нами ранее. Использовать ее с сервером не удастся, потому что данные передаются в виде буферных фрагментов.

Буферизация файла в памяти может создать проблемы с масштабированием, поэтому возможно другое решение: сохранить несжатый файл, распаковать его и затем удалить временный несжатый файл. Оставляю его для самостоятельной работы.

The post Сжатие / восстановление данных с использованием библиотеки Zlib appeared first on HackerX.

]]>
https://hackerx.ru/node-data-compression-library-zlib/feed/ 0
Node.js: Потоки (Stream) и pipe() https://hackerx.ru/node-js-stream-pipe/ https://hackerx.ru/node-js-stream-pipe/#respond Sun, 08 Jul 2018 08:45:41 +0000 https://hackerx.ru/?p=989 Потоковая технология проявляется во всех базовых аспектах Node; она предоставляет функциональность для HTTP, а также для других форм сетевой передачи данных. Кроме того, она предоставляет функциональность для файловой системы. Поток представлен абстрактным интерфейсом, это означает, что вы не будете создавать потоки напрямую. Вместо этого вы будете работать с различными объектами, реализующими интерфейс Stream, — запросами […]

The post Node.js: Потоки (Stream) и pipe() appeared first on HackerX.

]]>
Потоковая технология проявляется во всех базовых аспектах Node; она предоставляет функциональность для HTTP, а также для других форм сетевой передачи данных. Кроме того, она предоставляет функциональность для файловой системы.

Поток представлен абстрактным интерфейсом, это означает, что вы не будете создавать потоки напрямую. Вместо этого вы будете работать с различными объектами, реализующими интерфейс Stream, — запросами HTTP, потоками для чтения или записи модуля File System, объектами сжатия Zlib или process.stdout. Непосредственно реализовать Stream API вам придется только в одном случае: при создании собственной реализации потока.

Так как многие объекты в Node реализуют потоковый интерфейс, все потоки в Node обладают базовой функциональностью:

  • Изменение кодировки потоковых данных вызовом setEncoding.
  • Проверка возможности чтения и (или) записи данных в поток.
  • Перехват событий потоков (например, получения данных или закрытия подключения) с назначением функций обратного вызова для каждого события.
  • Приостановка и возобновление потока.
  • Перенаправление данных из потока для чтения в поток для записи.

Обратите внимание на пункт с проверкой чтения и (или) записи. Поток с поддержкой чтения и записи называется дуплексным. Также существует подвид дуплексных потоков, называемый потоком преобразования данных, в котором ввод и вывод связаны причинной зависимостью. Такая разновидность потоков будет описана позднее, когда я буду рассматривать сжатие Zlib.

Поток для чтения начинает работу в приостановленном состоянии; это означает, что никакие данные не будут отправляться до того момента, пока не будет явно выполнена операция чтения ( stream.read() ) или команда возобновления работы потока ( stream.resume() ). Однако используемые нами реализации потоков, такие как поток для чтения модуля File System, переключаются в рабочий режим сразу же при программировании события данных (механизм получения доступа к данным в потоке для чтения). В рабочем режиме данные передаются приложению сразу же при их появлении.



Потоки для чтения поддерживают несколько событий, но на практике нас обычно интересуют три события: data, end и error. Событие data отправляется при получении нового фрагмента данных, готового к использованию, а событие end — при потреблении всех данных. Событие error, естественно, отправляется при возникновении ошибки. Ниже вы увидите в примерах использование модуля File System.

Поток для записи представляет собой приемник, в который передаются (записываются) данные. Среди прослушиваемых событий можно выделить error и событие finish, происходящее при вызове end() и сбросе всех данных. Также встречается событие drain , генерируемое в тот момент, когда попытка записи данных возвращает false.

Дуплексный поток обладает качествами потоков как для чтения, так и для записи. Поток преобразования данных представляет собой дуплексный поток, в котором — в отличие от обычных дуплексных потоков, где внутренние входные и выходные буферы существуют независимо друг от друга, — эти два буфера связаны напрямую через промежуточный этап преобразования данных. Во внутренней реализации поток преобразования данных должен реализовать функцию _transform(), которая получает входные данные, что-то с ними делает, а затем записывает в вывод.

Чтобы лучше понять суть потока преобразования данных, необходимо поближе познакомиться с функциональностью, поддерживаемой всеми потоками: функцией pipe(). Пример ее использования представлен ниже, где поток для чтения напрямую связывал содержимое файла с объектом ответа HTTP:
Создание и перенаправление потока для чтения

const file = fs.createReadStream(pathname);
file.on("open", function() {
  file.pipe(res);
});

Вызов pipe() извлекает данные из файла (поток) и выводит их в объект http.ServerResponse. В документации Node указано, что этот объект реализует интерфейс потока для записи и, как будет показано позднее, fs.createReadStream() возвращает fs.ReadStream — реализацию потока для чтения. В число методов, поддерживаемых потоком для чтения, входит и pipe() с потоком для записи.

Скоро я добавлю (возможно уже добавил) статью / пример использования модуля Zlib для сжатия файла, а пока ограничимся кратким примером, отлично демонстрирующим применение потока преобразования данных:

const gzip = zlib.createGzip();
const fs   = require('fs');
const inp  = fs.createReadStream('input.txt');
const out  = fs.createWriteStream('input.txt.gz');

inp.pipe(gzip).pipe(out);

На вход поступает поток для чтения, на выходе находится поток для записи. Содержимое одного потока передается в другой, но сначала проходит через процедуру сжатия (это и есть преобразование).

The post Node.js: Потоки (Stream) и pipe() appeared first on HackerX.

]]>
https://hackerx.ru/node-js-stream-pipe/feed/ 0
Node.js — Модуль OS: Работа с операционной системой https://hackerx.ru/node-js-%d0%bc%d0%be%d0%b4%d1%83%d0%bb%d1%8c-os-%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%b0-%d1%81-%d0%be%d0%bf%d0%b5%d1%80%d0%b0%d1%86%d0%b8%d0%be%d0%bd%d0%bd%d0%be%d0%b9-%d1%81%d0%b8%d1%81%d1%82%d0%b5/ https://hackerx.ru/node-js-%d0%bc%d0%be%d0%b4%d1%83%d0%bb%d1%8c-os-%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%b0-%d1%81-%d0%be%d0%bf%d0%b5%d1%80%d0%b0%d1%86%d0%b8%d0%be%d0%bd%d0%bd%d0%be%d0%b9-%d1%81%d0%b8%d1%81%d1%82%d0%b5/#respond Sun, 08 Jul 2018 03:57:08 +0000 https://hackerx.ru/?p=983 Некоторым технологиям удается полностью маскировать различия между операционными системами. В других случаях для того, чтобы справиться со спецификой отдельных ОС, разработчику приходится основательно потрудиться. Node занимает промежуточное положение. Обычно приложения, созданные вами, работают в любых системах. Однако существует ряд функциональных областей, в которых проявляются различия между ОС. Иногда Node справляется с ними хорошо, а иногда […]

The post Node.js — Модуль OS: Работа с операционной системой appeared first on HackerX.

]]>
Некоторым технологиям удается полностью маскировать различия между операционными системами. В других случаях для того, чтобы справиться со спецификой отдельных ОС, разработчику приходится основательно потрудиться. Node занимает промежуточное положение. Обычно приложения, созданные вами, работают в любых системах. Однако существует ряд функциональных областей, в которых проявляются различия между ОС. Иногда Node справляется с ними хорошо, а иногда разработчику приходится прибегать к услугам удобных сторонних модулей.

Для непосредственного получения информации об операционной системе используется базовый модуль OS. Это один из полезных инструментов, упрощающих построение кросс-платформенных приложений. Кроме того, он предоставляет информацию об использовании ресурсов и возможностях текущей среды.

Обращение к модулю OS начинается с команды require, с помощью которого мы подключаем данный модуль:

const os = require('os');

Вся функциональность модуля OS направлена только на получение информации. Например, если вы хотите обеспечить кросс-платформенную поддержку, можно проверить, какой завершитель строки поддерживается текущей системой, использует она прямой (little-endian) или обратный (big endian) порядок байтов, а также узнать временный и домашний каталог:

const os = require('os');

console.log('Using end of line' + os.EOL + 'to insert a new line');
console.log(os.endianness());
console.log(os.tmpdir());
console.log(os.homedir());

На моем сервере с Ubuntu и компьютере с Windows 10 используется прямой порядок байтов, а завершитель строки (EOL, End-Of-Line) в обеих системах работает так, как и следовало ожидать (вторая часть текста начинается с новой строки). Различаются только временный и домашний каталоги, что вполне естественно.



Модуль OS также предоставляет средства для проверки доступных ресурсов текущей машины.

console.log(os.freemem());
console.log(os.loadavg());
console.log(os.totalmem());

Функция os.loadavg() специфична для Unix; в Windows она просто возвращает нули. Она возвращает показатель средней загрузки, отражающий текущую интенсивность работы системы, за 1, 5 и 15 минут. Чтобы получить значения в процентах, умножьте числа на 100.

Функции os.freemen() и os.totalmem() возвращают объем памяти в байтах.

Другая функция, os.cpus(), возвращает информацию о процессорах машины. Возвращается количество миллисекунд, проведенных процессором в разных режимах: user, nice, sys, idle и irq. Если вы не знакомы с этими концепциями: значение user определяет время, проведенное процессором за выполнением процессов пользовательского пространства, idle — время бездействия, а sys — время, проведенное за выполнением системных процессов (режим ядра). Значение nice отражает величину динамической регулировки приоритета, предотвращающей слишком частое его выполнение. Значение irq описывает прерывания — запросы на обслуживание на аппаратном уровне.

Время в миллисекундах не так удобно, как проценты. Чтобы определить их, можно просуммировать все значения, а затем вычислить проценты. Также можно воспользоваться модулями независимых разработчиков, которые возвращают значения в процентах (наряду с другой информацией).

The post Node.js — Модуль OS: Работа с операционной системой appeared first on HackerX.

]]>
https://hackerx.ru/node-js-%d0%bc%d0%be%d0%b4%d1%83%d0%bb%d1%8c-os-%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%b0-%d1%81-%d0%be%d0%bf%d0%b5%d1%80%d0%b0%d1%86%d0%b8%d0%be%d0%bd%d0%bd%d0%be%d0%b9-%d1%81%d0%b8%d1%81%d1%82%d0%b5/feed/ 0
Webpack и Node.js: Руководство по использованию https://hackerx.ru/webpack-and-nodejs/ https://hackerx.ru/webpack-and-nodejs/#respond Fri, 06 Jul 2018 11:06:19 +0000 https://hackerx.ru/?p=973 Введение: Что такое Webpack Разрабатывая приложения для платформы Node.js, старайтесь не использовать си­стем модулей, отличных от той, что предлагается по умолчанию. В идеале нужно продолжать писать модули как обычно, используя require() и module.exports, а затем применять инструмент для преобразования кода в пакет, который будет нормально работать в браузере. К счастью, эта задача имеет множество решений, самым […]

The post Webpack и Node.js: Руководство по использованию appeared first on HackerX.

]]>
Введение: Что такое Webpack

Разрабатывая приложения для платформы Node.js, старайтесь не использовать си­стем модулей, отличных от той, что предлагается по умолчанию. В идеале нужно продолжать писать модули как обычно, используя require() и module.exports, а затем применять инструмент для преобразования кода в пакет, который будет нормально работать в браузере. К счастью, эта задача имеет множество решений, самым попу­ярным из которых является Webpack (https://webpack.github.io).

Webpack позволяет создавать модули с использованием соглашений о модулях Node.js, с последующей компиляцией в пакет (единственный JavaScript-файл), со­держащий все необходимое для работы в браузере (в том числе абстрактные функции require()). Такой пакет затем можно включить в веб-страницу, как обычно, и выпол­нить в браузере. Webpack рекурсивно сканирует исходный код, отыскивает ссылки на функцию require(), разрешает их и добавляет нужные модули в пакет.

Установка и знакомство с Webpack

Для быстрой демонстрации волшебства Webpack рассмотрим, как будет выглядит обычный Node.js модуль при использовании этого инст­румента. Во-первых, необходимо установить сам Webpack, что можно сделать с по­мощью следующей простой команды:

npm install webpack -g

Параметр -g указывает npm, что необходимо установить Webpack глобально, чтобы его можно было использовать из консоли, как будет показано ниже.

Далее, создадим новый проект и попробуем написать модуль. Вот так будет выглядеть его реализация для платформы Node.js (файл sayHello.js):

var mustache = require('mustache');
var template = '<h1>Hello <i>{{name}}</i></h1>';
mustache.parse(template);
module.exports.sayHello = function(toWhom) {
  return mustache.render(template, {name: toWhom});
};

Теперь создадим файл main.js, то есть точку входа в код для браузера:

window.addEventListener('load', function(){
  var sayHello = require('./sayHello').sayHello;
  var hello = sayHello('Browser!');
  var body = document.getElementsByTagName("body")[0];
  body.innerHTML = hello;
});

В приведенном выше коде загрузка модуля sayHello выполняется точно так же, как в Node.js, нет никаких дополнительных сложностей при управлении зависимостями и настройке путей, поскольку всю работу выполняет обычная функция require().

Добавим зависимость mustache в проект:

npm install mustache

А теперь волшебное действие. Запустим следующую команду в терминале:

webpack main.js bundle.js

Она скомпилирует модуль main и соберет все необходимые зависимости в один файл bundle.js, готовый к использованию в браузере!



Чтобы быстро проверить работоспособность получившегося пакета, создадим HTML-страницу magic.html со следующим кодом:

<html>
  <head>
    <title>Webpack magic</title>
    <script src="bundle.js"></script>
  </head>
  <body>
  </body>
</html>

Этого достаточно для выполнения кода в браузере. Попробуйте открыть страницу и взгляните сами. Ура!

Преимущества использования Webpack

Волшебство Webpack этим не ограничивается. Вот (неполный) перечень функцио­ нальных возможностей, которые упрощают совместное использование кода с браузером:

  • Webpack автоматически предоставляет версии многих модулей ядра Node.js, совместимые с браузером. Это означает, что в браузере можно использовать такие модули, как http, assert, events, и многие другие!
  • Если имеется модуль, несовместимый с браузером, его можно исключить из сборки, заменить пустым объектом или другим модулем с альтернативной реа­лизацией, которая совместима с браузером. Это играет решающую роль, и дан­ная возможность будет использоваться в примере ниже;
  • Webpack может генерировать пакеты для различных модулей;
  • Webpack позволяет выполнять дополнительную обработку исходных файлов с помощью сторонних загрузчиков и плагинов. Имеются загрузчики и пла­гины практически для всего, что может понадобиться, от компиляции Cof­feeScript, TypeScript и ES2015 до поддержки загрузки AMD, пакетов Bower (http://bower.io) и Component (http://component.github.io), использующих require(), от минификации до компиляции и упаковки других ресурсов, таких как шаблоны и таблицы стилей;
  • Webpack с легкостью можно вызывать из диспетчеров заданий, таких как Gulp (https://npmjs.com/package/gulp-webpack) и Grunt (https://npmjs.org/package/grunt-webpack);
  • Webpack позволяет управлять и выполнять предварительную обработку ресур­сов проекта, причем не только JavaScript-файлов, но и таблиц стилей, изобра­жений, шрифтов и шаблонов;
  • кроме того, Webpack можно настроить для разделения дерева зависимостей на несколько частей, которые будут загружаться по требованию, когда они пона­добятся браузеру.

Потенциал и гибкость Webpack настолько привлекательны, что многие разработчи­ки начали использовать его даже для управления кода, предназначенного только для выполнения на стороне клиента. Это стало возможным потому, что многие клиентские библиотеки начали по умолчанию поддерживать CommonJS и npm, что открывает но­вые и очень интересные перспективы. Например, можно установить библиотеку jQuery:

npm install jquery

а затем загрузить ее с помощью простой строки кода:

const $ = require('jquery');

Вы будете удивлены, как много клиентских библиотек уже поддерживают CommonJS и Webpack.

The post Webpack и Node.js: Руководство по использованию appeared first on HackerX.

]]>
https://hackerx.ru/webpack-and-nodejs/feed/ 0
Глобальные объекты: Объекты global и process https://hackerx.ru/node-global-objects/ https://hackerx.ru/node-global-objects/#respond Fri, 20 Apr 2018 08:33:13 +0000 https://hackerx.ru/?p=960 Два важнейших объекта в Node — global и process . Объект global немного похож на глобальный объект в браузере, хотя между ними существуют очень серьезные различия. Объект process , напротив, существует только в Node. Объект global В браузере переменная, объявленная на верхнем уровне, объявляется глобально. В Node дело обстоит иначе. Переменная, объявленная в модуле или […]

The post Глобальные объекты: Объекты global и process appeared first on HackerX.

]]>
Два важнейших объекта в Node — global и process . Объект global немного похож на глобальный объект в браузере, хотя между ними существуют очень серьезные различия. Объект process , напротив, существует только в Node.

Объект global

В браузере переменная, объявленная на верхнем уровне, объявляется глобально. В Node дело обстоит иначе. Переменная, объявленная в модуле или приложении Node, не обладает глобальной доступностью; она ограничивается модулем или приложением. Таким образом, можно объявить «глобальную» переменную с именем str в модуле и в приложении, использующем этот модуль, и никакого конфликта не будет.

Для демонстрации создадим простую функцию, которая прибавляет число к базовому значению и возвращает результат (название файла — add2.js). Функция будет создана как библиотека JavaScript для использования в веб странице, а также как модуль для использования в приложении Node. Код объявляет переменную base, присваивает ей значение 2, после чего прибавляет переданное число:

var base = 2;
function addtwo(input) {
  return parseInt(input) + base;
}

Затем создадим очень простой модуль (название файла — addtwo.js), который делает то же самое, но с использованием синтаксиса модуля Node.

var base = 2;
exports.addtwo = function(input) {
  return parseInt(input) + base;
};

А теперь посмотрим, чем различается концепция глобальности в двух разных средах. Файл add2.js используется в веб-странице, которая также объявляет переменную base:

<!DOCTYPE html>
<html>
 <head>
  <script src="add2.js"></script>
  <script>
   var base = 10;
   console.log(addtwo(10));
  </script>
 </head>
 <body>
 </body>
</html>

При обращении к веб-странице в браузере на консоли браузера выводится значение 20 (вместо ожидаемого 12). Дело в том, что все переменные, объявленные за пределами функции в JavaScript, добавляются в один глобальный объект. Объявляя новую переменную с именем base в веб странице, мы переопределяем значение во включенном файле сценария.

Теперь используем модуль addtwo в приложении Node:

var addtwo = require('./addtwo').addtwo;
var base = 10;
console.log(addtwo(base));

В приложении Node результат равен 12. Объявление новой переменной басе в приложении Node никак не повлияло на значение base в модуле, потому что они существуют в разных глобальных пространствах имен.

Устранение общего пространства имен — безусловное усовершенствование, но оно не универсально. Объект global во всех средах предоставляет доступ к глобально доступным объектам и функциям Node , включая объект процесс (см. далее). Чтобы убедиться в этом, просто добавьте следующую команду в файл и запустите приложение. Команда выводит все глобально доступные объекты и функции:

console.log(global);



Объект process

Объект process принадлежит к числу важнейших компонентов среды Node, так как он предоставляет информацию о среде выполнения. Кроме того, через объект process выполняется стандартный ввод/вывод, вы можете корректно завершить приложение Node и даже выдать сигнал при завершении итерации в цикле событий Node.

Сейчас мы рассмотрим получение информации о среде выполнения объекта process, а также исключительно важные средства стандартного ввода/вывода.

Объект process предоставляет доступ к информации как о среде Node, так и о среде выполнения программы. Для получения информации мы воспользуемся параметром командной строки -p , который выполняет сценарий и возвращает полученный результат. Например, для проверки свойства process. versions введите следующую команду:

$ node -p "process.versions"

{ http_parser: ‘2.5.0’,
node: ‘4.2.1’,
v8: ‘4.5.103.35’,
uv: ‘1.7.5’,
zlib: ‘1.2.8’,
ares: ‘1.10.1-DEV’,
icu: ‘56.1’,
modules: ’46’,
openssl: ‘1.0.2d’ }

Команда выводит список различных компонентов Node и зависимостей, включая версии v8, OpenSSL (библиотека, используемая для безопасной передачи данных), собственно Node и т. д.

Свойство process.env предоставляет богатую информацию о том, что Нодье знает о вашей среде разработки:

$ node -p "process.env"

Особенно интересно проанализировать различия между архитектурами (например, Linux и Windows).

Чтобы просмотреть содержимое process.release, введите следующую команду:

$ node -p "process.release"

Полученный результат зависит от того, что установлено на вашем компьютере. И в LTS, и в среде текущей версии будет выведено имя приложения, а также URL исходного кода. Но в LTS также будет выведено дополнительное свойство:

$ node -p «process.release.lts»
‘Argon’

Однако при обращении к тому же значению в текущей версии (например, v6) будет получен другой результат:

$ node -p «process.release.lts»
undefined

Информация о среде позволяет разработчику понять, что видит Node до и после разработки. Не включайте зависимости от этих данных прямо в приложение, потому что, как вы уже видели, они могут различаться между версиями Node. Тем не менее не жалейте времени на анализ этих данных.

Между версиями Node в любом случае должны остаться неизменными основные объекты и функции, важные для работы приложений. В их числе стандартный ввод/вывод и возможность корректного завершения приложения Node.

Стандартные потоки представляют собой заранее определенные каналы передачи данных между приложением и средой: стандартный ввод ( stdin ), стандартный вывод ( stdout ) и стандартный поток ошибок ( stderr ). В приложении Node эти каналы обеспечивают взаимодействие между приложением Нодье и терминалом, своего рода механизм прямого «общения» с приложением.

Node поддерживает каналы с тремя функциями process:

  • process.stdin : поток с поддержкой чтения для stdin;
  • process.stdout : поток с поддержкой записи для stdout;
  • process.stderr : поток с поддержкой записи для stderr.

Вы не можете закрывать эти потоки в своем приложении. Поддерживается только чтение данных из канала stdin и запись в каналы stdout и stderr.

Функции ввода/вывода process наследуют от EventEmitter, это означает, что они могут генерировать события, а вы можете перехватывать эти события и обрабатывать любые данные. Чтобы обработать входные данные с использованием process.stdin , прежде всего необходимо назначить кодировку потока. Если этого не сделать, вы получите результаты в виде буфера, а не в виде строки:

process.stdin.setEncoding('utf8');

Затем начинается прослушивание события readable , которое сообщает о поступлении блока данных, готового к чтению. Затем функция process.stdin. read() используется для чтения данных, и если данные отличны от null, они копируются в process.stdout при помощи функции process.stdout.write():

process.stdin.on('readable', function() {
  var input = process.stdin.read();
  if (input !== null) {
    // Эхо-вывод текста
    process.stdout.write(input);
  }
});

В принципе можно пропустить назначение кодировки и получить те же результаты; программа будет читать буфер и выводить буфер, но для пользователя приложения все выглядит так, словно вы работаете с текстом (строка). На самом деле это не так. Следующая функция process , которую мы рассмотрим, демонстрирует эти различия.

Мы раньше создали очень простой веб-сервер, который прослушивал запрос и выводил сообщение. Чтобы завершить программу, вам придется либо уничтожить процесс с использованием сигнала, либо нажать клавиши Ctrl+C. Также возможен другой вариант: завершить приложение из кода самого приложения при помощи process.exit() . Вы даже можете передать информацию о том, успешно ли завершилось приложение или произошла ошибка.

Мы изменим тестовое приложение ввода/вывода так, чтобы оно «прослушивало» строку выхода и при ее обнаружении программа завершалась.

process.stdin.setEncoding('utf8');

process.stdin.on('readable', function() {
  var input = process.stdin.read();
  if (input !== null) {
    // Эхо-вывод текста
    process.stdout.write(input);
    var command = input.trim();
    if (command == 'exit')
      process.exit(0);
  }
});

Если запустить это приложение, любая введенная строка будет немедленно повторяться в выводе. А если ввести команду exit , то приложение завершается, не требуя нажатия Ctrl+C.

Если убрать вызов функции process.stdin.setEncoding() в начале кода, произойдет ошибка. Дело в том, что буферы не поддерживают функцию trim(). Можно преобразовать буфер в строку, а затем выполнить trim:

var command = input.toString().trim();

Но лучше просто добавить команду назначения кодировки и исключить все неожиданные побочные эффекты.

Запись в объект process.stderr выполняется при возникновении ошибки. Почему именно этот объект, а не process.stdout ? По той же причине, по которой был создан канал stderr: чтобы отделить ожидаемый вывод от возникающих проблем. В некоторых системах вывод stderr даже может обрабатываться отдельно от stdout (например, сообщения stdout сохраняются в журнале, а вывод stderr выводится на консоль).

The post Глобальные объекты: Объекты global и process appeared first on HackerX.

]]>
https://hackerx.ru/node-global-objects/feed/ 0
ICO — Telegram Open Network (TON). Криптовалюта / Token Gram https://hackerx.ru/ico-ton/ https://hackerx.ru/ico-ton/#respond Thu, 08 Mar 2018 06:58:40 +0000 https://hackerx.ru/?p=950 В этой статье я расскажу, что такое Telegram Open Network (TON), что такое токены / криптовалюта Gram. Зачем Телеграмму ICO? Если вы пользуетесь этим мессенджером то наверняка заметили отсутствие рекламы, а возможно слышали громкие заявления Павла Дурова о том, что никакой рекламы не будет. Это может означать только одно, что проект в данный момент не приносит доход, […]

The post ICO — Telegram Open Network (TON). Криптовалюта / Token Gram appeared first on HackerX.

]]>
В этой статье я расскажу, что такое Telegram Open Network (TON), что такое токены / криптовалюта Gram.

Зачем Телеграмму ICO? Если вы пользуетесь этим мессенджером то наверняка заметили отсутствие рекламы, а возможно слышали громкие заявления Павла Дурова о том, что никакой рекламы не будет. Это может означать только одно, что проект в данный момент не приносит доход, но при этом требует существенных вложений от своего создателя. Один из самых перспективных способов выйти из сложившийся ситуации, это интегрировать в Telegram криптовалюту, как это сделал WeChat с NEM.

Криптовалюта / токен Telegram получит название GRAM, а сама блокчейн-платформа будет именоваться TON (Telegram Open Network). К 2021 году после создания полноценной блокчейн-экосистемы и внутренней экономики Telegram Open Network сменит название на The Open Network.

Почему вокруг ICO Телеграмм так много хайпа

Такого масштабного проекта еще не было в истории ICO, это конечно большой шаг в развитии криптовалюты и не удивительно, что многие пророчат большую прибыль инвесторам и оснований для этого предостаточно:

  • Продукт
    Не каждое ICO на момент проведения имеет готовый прототип своего продукта, на этом фоне Телеграмм со своим лучшим на данный момент мессенджером выглядит впечатляюще.
  • Аудитория
    200 миллионов пользователей, на данный момент. Если вы интересуетесь криптовалютой, то для вас не секрет, что в основном все общение криптоэнтузиастов происходит в Telegram. Ни одно ICO не обходится без группы или канала в этом мессенджере.
  • Команда
    Павел Дуров — основатель ВКонтакте, является авторитетной фигурой в IT мире, только его участие может создать ажиотаж, а если взглянуть на всю команду, включающую Николай Дурова и других призеров мировых чемпионатов по программированию, то становится ясно откуда так много хайпа и желающих инвестировать свои деньги в проект.

Дата выхода анонса TON и GRAM: ориентировочно в марте 2018 года;
Полный запуск экосистемы Blockchain TON: Q2 2019;
Общая эмиссия монет GRAM: 5 млрд. токенов;

  • 4% (200 млн. токенов) зарезервированы для команды разработчиков;
  • 52% (2,6 млрд. токенов) криптовалюты GRAM изначально будут заморожены (для избежания резкой волатильности стоимости);
  • 44% (2,2 млрд. токенов) поступят в свободную продажу;
  • Ориентировочно после 2020-го раз в год будет дополнительно выпускаться по 100 000 000 токенов GRAM;

Pre-ICO TON: Q1 2018, минимальная сумма от $20 млн. (стоимость монеты от $0,38)
Pre-ICO-2 (второй этап) TON: Q1 2018, минимальная сумма от $1 млн. для физлиц и от $10 для юр.лиц. (стоимость монеты от $1,33).

Зачем нужен Gram

Самые очевидные способы применения могут быть такими:

  • Кошелек — хранение криптовалюты в мессенджере, анонимно, без участия банков и бюрократической волокиты.
  • Покупка, продажа — купить или продать товар мгновенно, прямо в чате.
  • Переводы — обмен граммами друг с другом без задержек и справок о происхождении денежных средств.
  • Подписка — пожертвования, доступ к платному контенту, каналу или группе.
  • Боты — смогут использовать технологии blockchain.
  • Своя криптовалюта — любой желающий сможет создать собственные токены на платформе TON и организовать ICO.

Как купить GRAM

Попасть на Pre-ICO Telegram простым смертным практически не реально, если конечно у вас не завалялись миллионов 20 долларов, так что придется ждать публичной продажи или объединяться в пул, чтобы собрать минимальную необходимую сумму. Если вы решитесь на такой шаг, то будьте крайне осторожны, скорее всего человек предложивший передать ваши деньги Павлу будет мошенником! Во время открытого ICO мессенджер намерен продать токенов на сумму от 3 до 5 миллиардов долларов, но в продажу поступят не все токены, а только 44%, часть оставят разработчикам 4%, а львиную долю 52% сохранят в качестве резерва.

Дорожная карта Telegram Open Network:

  • Q1 2018 — Launch of Telegram External Secure ID (Запуск внешнего кода безопасности)
  • Q2 2018 — Launch of the Minimal Viable Test Network of TON (Тестирование сети TON по принципу MVP — «Минимально Жизнеспособный Продукт»)
  • Q3 2018 — Testing and security audits of TON (Тестирование и проверка безопасности TON)
  • Q4 2018 — Deployment of the stable version of TON (Внедрение стабильной версии блокчейна TON)
  • Q4 2018 — Launch of Telegram Wallet (Запуск Телеграм Кошелька)
  • Q1 2019 — Creation of TON-based economy in Telegram (Создание экономики, основанной на блокчейне Telegram Open Network)
  • Q1 2019 — Launch of TON Services, TON Storage, and TON Proxy (Запуск служб, хранилища и прокси-серверов TON)

The post ICO — Telegram Open Network (TON). Криптовалюта / Token Gram appeared first on HackerX.

]]>
https://hackerx.ru/ico-ton/feed/ 0
Machine Learning: Зачем нужно машинное обучение https://hackerx.ru/machine-learning-python/ https://hackerx.ru/machine-learning-python/#respond Thu, 07 Dec 2017 15:29:12 +0000 https://hackerx.ru/?p=933 На заре появления «интеллектуальных» приложений многие системы использовали жесткие правила «if» и «else» для обработки данных или корректировки информации, введенной пользователем. Вспомните о спам фильтре, чья работа состоит в том, чтобы переместить соответствующие входящие сообщения электронной почты в папку «Спам». Вы можете составить черный список слов, которые будут идентифицировать письмо как спам. Это пример использования […]

The post Machine Learning: Зачем нужно машинное обучение appeared first on HackerX.

]]>
На заре появления «интеллектуальных» приложений многие системы использовали жесткие правила «if» и «else» для обработки данных или корректировки информации, введенной пользователем. Вспомните о спам фильтре, чья работа состоит в том, чтобы переместить соответствующие входящие сообщения электронной почты в папку «Спам». Вы можете составить черный список слов, которые будут идентифицировать письмо как спам. Это пример использования системы экспертных правил для разработки «интеллектуального» приложения. Разработка правил принятия решений в ручном режиме допустимо в некоторых задачах, особенно в тех, где люди четко понимают процесс моделирования. Однако, использование жестких решающих правил имеет два основных недостатка:

  • Логика, необходимая для принятия решения, относится исключительно к одной конкретной области и задачи. Даже несущественное изменение задачи может повлечь за собой переписывание всей системы.
  • Разработка правил требует глубокого понимания процесса принятия решения.

Один из примеров, где этот жесткий подход потерпит неудачу – это распознавание лиц на изображениях. На сегодняшний день каждый смартфон может распознать лицо на изображении. Тем не менее, распознавание лиц была нерешенной проблемой, по крайней мере, до 2001 года. Основная проблема заключается в том, что способ, с помощью которого компьютер «воспринимает» пиксели, формирующие изображение на компьютере, очень сильно отличается от человеческого восприятия лица. Эта разница в принципе не позволяет человеку сформулировать подходящий набор правил, описывающих лицо с точки зрения цифрового изображения.

Однако, благодаря машинному обучению, простого предъявления большого количества изображений с лицами будет достаточно для того, чтобы алгоритм определил, какие признаки необходимы для идентификации лица.


Какие задачи можно решить с помощью машинного обучения

Наиболее успешные алгоритмы машинного обучения – это те, которые автоматизируют процессы принятия решений путем обобщения известных примеров. В этих методах, известных как обучение с учителем или контролируемое обучение ( supervised learning ), пользователь предоставляет алгоритму пары объект-ответ, а алгоритм находит способ получения ответа по объекту. В частности, алгоритм способен выдать ответ для объекта, которого он никогда не видел раньше, без какой-либо помощи человека. Если вернуться к примеру классификации спама с использованием машинного обучения, пользователь предъявляет алгоритму большое количество писем (объекты) вместе с информацией о том, является ли письмо спамом или нет (ответы). Для нового электронного письма алгоритм вычислит вероятность, с которой это письмо можно отнести к спаму.

Алгоритмы машинного обучения, которые учатся на парах объект-ответ, называются алгоритмами обучения с учителем, так как «учитель» показывает алгоритму ответ в каждом наблюдении, по которому происходит обучение. Несмотря на то, что создание набора с объектами и ответами – это часто трудоемкий процесс, осуществляемый вручную, алгоритмы обучения с учителем интерпретируемы и качество их работы легко измерить. Если вашу задачу можно сформулировать в виде задачи обучения с учителем, и вы можете создать набор данных, который включает в себя ответы, вероятно, машинное обучение решит вашу проблему.

Примеры задач машинного обучения с учителем:

Определение почтового индекса по рукописным цифрам на конверте.

Здесь объектом будет сканированное изображение почерка, а ответ – фактические цифры почтового индекса. Чтобы создать набор данных для построения модели машинного обучения, вам нужно собрать большое количество конвертов. Затем вы можете самостоятельно прочитать почтовые индексы и сохранить цифры в виде ответов.

Определение доброкачественности опухоли на основе медицинских изображений.
Здесь объектом будет изображение, а ответом – диагноз, является ли опухоль доброкачественной или нет. Чтобы создать набор данных для построения модели, вам нужна база медицинских изображений. Кроме того, необходимо мнение эксперта, поэтому врач должен просмотреть все изображения и решить, какие опухоли являются доброкачественными, а какие – нет. Помимо анализа изображения может понадобиться дополнительная диагностика для определения доброкачественности опухоли.

Обнаружение мошеннической деятельности в сделках по кредитным картам.
Здесь объект – запись о транзакции по кредитной карте, а ответ — информация о том, является ли транзакция мошеннической или нет. Предположим, вы – учреждение, выдающее кредитные карты, сбор данных подразумевает сохранение всех транзакций и запись сообщений клиентов о мошеннических транзакциях.

Приведя эти примеры, интересно отметить что, хотя объекты и ответы выглядят достаточно просто, процесс сбора данных для этих трех задач существенно отличается. Несмотря на то что чтение конвертов является трудоемким занятием, этот процесс прост и дешев. Получение медицинских изображений и проведение диагностики требует не только дорогостоящего оборудования, но и редких, высокооплачиваемых экспертных знаний, не говоря уже об этических проблемах и вопросах конфиденциальности. В примере обнаружения мошенничества с кредитными картами, сбор данных осуществляется намного проще. Ваши клиенты сами предоставят вам ответы, сообщая о мошенничестве. Все, что вам нужно сделать для получения объектов и ответов, связанных с мошеннической активностью, – это подождать.

Алгоритмы обучения без учителя или неконтролируемого обучения (unsupervised algorithms) – это еще один вид алгоритмов, который мы рассмотрим в этой книге. В алгоритмах обучения без учителя известны только объекты, а ответов нет. Хотя есть много успешных сфер применения этих методов, их, как правило, труднее интерпретировать и оценить.

Примеры задач машинного обучения без учителя:

Определение тем в наборе постов.
Если у вас есть большая коллекция текстовых данных, вы можете агрегировать их и найти распространенные темы. У вас нет предварительной информации о том, какие темы там затрагиваются и сколько их. Таким образом, нет никаких известных ответов.

Сегментирование клиентов на группы с похожими предпочтениями.
Имея набор записей о клиентах, вы можете определить группы клиентов со схожими предпочтениями. Для торгового сайта такими группами могут быть «родители», «книгочеи» или «геймеры». Поскольку вы не знаете заранее о существовании этих групп и их количестве, у вас нет ответов.

Обнаружение паттернов аномального поведения на веб-сайте.
Чтобы выявить злоупотребления или ошибки, часто бывает полезно найти паттерны поведения, которые отличаются от нормы. Паттерны аномального поведения могут быть разными, и, возможно, у вас не будет зарегистрированных случаев аномального поведения. Поскольку в этом примере вы наблюдаете лишь трафик, и вы не знаете, что представляет собой нормальное и ненормальное поведение, речь идет о задаче обучения без учителя.

The post Machine Learning: Зачем нужно машинное обучение appeared first on HackerX.

]]>
https://hackerx.ru/machine-learning-python/feed/ 0
Как создать собственные модули в Node.js и опубликовать в NPM https://hackerx.ru/node-js-npm-module/ https://hackerx.ru/node-js-npm-module/#respond Fri, 24 Nov 2017 12:37:45 +0000 https://hackerx.ru/?p=916 До того, как мы начнём разработать собственные модули в Node.js, давайте познакомимся с NPM. Узнаем что такое NPM, для чего он может понадобиться нам, как с ним можно работать, ознакомимся с основными командами и сделаем несколько важных настроек. Содержимое: Знакомство с NPM Создание и публикация собственных модулей Node Создание модуля Упаковка целого каталога Подготовка модуля к публикации Публикация модуля Знакомство с NPM […]

The post Как создать собственные модули в Node.js и опубликовать в NPM appeared first on HackerX.

]]>
До того, как мы начнём разработать собственные модули в Node.js, давайте познакомимся с NPM. Узнаем что такое NPM, для чего он может понадобиться нам, как с ним можно работать, ознакомимся с основными командами и сделаем несколько важных настроек.
Содержимое:

Знакомство с NPM

Значительная часть обширной функциональности, связанной с Node, реализована в модулях независимых разработчиков. Это модули маршрутизации, модули для работы с реляционными и документными СУБД, модули шаблонов, модули тестирования и даже модули платежных сервисов.

Чтобы использовать модуль, вы можете загрузить его исходный код, а затем установить его вручную в своей среде. Многие модули содержат базовые инструкции по установке, или, как минимум, требования к установке можно вычислить просмотром файлов и каталогов, включенных в модуль. Однако существует куда более простой способ установки модулей Node — менеджер npm.

Node.js поставляется с установленной копией npm, но эта версия npm не всегда является самой новой. Если вы захотите использовать другую версию npm, введите следующую команду для обновления имеющейся версии (используйте sudo , если этого требует ваша система):

npm install npm -g

Чтобы получить подробную сводку команд npm, воспользуйтесь следующей командой:

npm help npm

Модули могут устанавливаться глобально или локально. Локальная установка лучше всего подходит для работы над изолированным проектом, когда всем остальным пользователям той же системы доступ к модулю не нужен. При локальной установке (а этот вариант используется по умолчанию) модуль устанавливается в текущей позиции каталога node_modules.

npm install имя_модуля

Например, для установки Express используется следующая команда:

npm install express

Программа npm не только устанавливает модуль Express, но и находит модули, от которых он зависит, и устанавливает их. Чем сложнее модуль, тем больше зависимостей устанавливается.

После того как модуль будет установлен, он будет находиться в каталоге node_modules вашего локального каталога. Все зависимости также будут установлены в каталог node_modules этого модуля.

Чтобы установить пакет глобально, используйте параметр -g или —global :

npm install express -g

Если вы работаете в системе Linux, не забудьте использовать sudo для глобальной установки модуля.

Если пакет существует в нескольких версиях, есть возможность установить конкретную версию:

npm install module_name@0.3

Если модуль больше не используется, его можно удалить:

npm uninstall имя_модуля

Следующая команда приказывает npm проверить наличие новых модулей и обновить найденные:

npm update

Также можно обновить один модуль:

npm update имя_модуля

А если вы хотите узнать, есть ли среди пакетов устаревшие, воспользуйтесь командой:

npm outdated

Для вывода списка всех установленных пакетов и зависимостей передайте параметр list , ls , la или ll :

npm ls

С параметрами la и ll команды выводят расширенные описания. Например, в число зависимостей Request входит tunnel-agent@0.4.1 (версия 0.4.1 пакета tunnel-agent). Что это вообще такое — tunnel-agent? Ввод запроса npm la в командной строке выводит список всех зависимостей, включая tunnel-agent, с дополнительной информацией:

tunnel-agent@0.4.1
HTTP proxy tunneling agent. Formerly part of mikeal/request,
now a standalone module
git+https://github.com/mikeal/tunnel-agent.git
https://github.com/mikeal/tunnel-agent#readme

Флаг -d устанавливает все зависимости напрямую. Например, в каталоге модуля введите команду:

npm install -d

Чтобы узнать, какие модули установлены глобально, используйте следующую команду:

npm ls -g

Для получения дополнительной информации об установке npm используйте команду config. Следующая команда выводит список параметров конфигурации npm:

npm config list

Более подробное описание всех параметров конфигурации выводится командой:

npm config ls -l

Изменение или удаление параметров конфигурации из командной строки осуществляется либо командой:

npm config delete ключ
npm config set ключ значение

Также можно провести поиск модуля по условиям, которые, как вы думаете, могут вернуть лучший результат:

npm search html5 parser

При первом проведении поиска npm строит индекс, на что может потребоваться несколько минут. Впрочем, после завершения индексирования вы получаете список возможных модулей, соответствующих заданному условию (или условиям).

Сайт npm предоставляет реестр модулей с возможностью просмотра и регулярно обновляемый список модулей, чаще всего используемых другими модулями или приложениями Node. В следующем разделе я приведу подборку таких модулей.

И последнее замечание по поводу npm перед тем, как двигаться дальше. В самом начале ваших экспериментов с npm в конце вывода могут появляться предупреждения. В первой строке сообщается о том, что файл package.json не найден, а в остальных содержатся всевозможные предупреждения, связанные с отсутствующим файлом package.json .

Документация npm рекомендует создать файл package.json для сопровождения локальных зависимостей. В принципе, это не обязательно, но предупреждения слегка раздражают.

Чтобы создать файл package.json по умолчанию в каталоге проекта, выполните следующую команду:

npm init --yes

Команда создает в каталоге файл package.json по умолчанию; при этом вам будет предложено ответить на ряд вопросов по проекту: ваше имя, название проекта и т. д., причем у каждого вопроса имеется значение по умолчанию. В дальнейшем при установке модуля вы уже не будете получать часть раздражающих сообщений. Чтобы избавиться от остальных, необходимо обновить данные JSON в этом файле и включить в них описание и информацию о репозитории. Кроме того, если вы хотите, чтобы файл обновлялся при установке обновленного модуля, используйте следующий синтаксис:

npm install express --save-dev

Имя и версия модуля сохраняются в поле devDependencies файла package.json. Также можно сохранить модуль в зависимостях модулей, но об этом подробнее я расскажу в следующей части этой статьи.

Создание и публикация собственных модулей Node

Как и в случае с кодом JavaScript на стороне клиента, многократно используемый код JavaScript стоит выделить в собственные библиотеки. Единственное отличие заключается в том, что вам придется выполнить пару лишних действий для преобразования библиотеки JavaScript в модуль, рассчитанный на взаимодействие с Node.



Создание модуля

Допустим, у вас имеется библиотечная функция JavaScript concatArray, которая получает строку и массив строк, выполняет конкатенацию первой строки с каждой строкой в массиве и возвращает новый массив:

function concatArray(str, array) {
  return array.map(function(element) {
    return str + ' ' + element;
  });
}

Вы хотите использовать эту функцию наряду с другими в своих приложениях Node. Чтобы преобразовать библиотеку JavaScript для использования в Node, необходимо экспортировать все функции с помощью объекта exports , как показано в следующем примере:

exports.concatArray = function(str, array) {
  return array.map(function(element) {
    return str + ' ' + element;
  });
};

Чтобы использовать concatArray в приложении Node, импортируйте библиотеку. После этого вы сможете использовать экспортированную функцию в своем приложении:

const newArray = require('./arrayfunctions.js');
let data = newArray.concatArray('hello', ['test1','test2']);
console.log(data);

Вы также можете создать модуль, состоящий из конструктора или функции, и экспортировать его с использованием module.exports.

Например, модуль Mime , от которого могут зависеть многие другие модули, создает функцию Mime():

function Mime() { ... }

добавляет функциональность с использованием свойства prototype :

Mime.prototype.define = function(map) {...}

создает экземпляр по умолчанию:

const mime = new Mime();

присваивает функцию Mime одноименному свойству:

mime.Mime = Mime;

и после этого экспортирует экземпляр:

module.exports = mime;

После этого вы сможете использовать различные функции Mime в своем приложении:

const mime = require('mime');
console.log(mime.lookup('phoenix5a.png');

Упаковка целого каталога

Вы можете разбить свой модуль на несколько файлов JavaScript, находящихся в каталоге. Node может загружать содержимое каталогов при условии, что его содержимое организовано одним из двух способов.

Первый способ основан на создании файла package.json с информацией о каталоге. Структура содержит разнообразную информацию, но к упаковке модуля относятся два свойства — name и main:

{
  "name": "mylibrary",
  "main": "./mymodule/mylibrary.js"
}

Первое свойство, name , содержит имя модуля, а второе свойство, main, обозначает точку входа модуля.

Во втором способе загрузки содержимого в каталог добавляется файл index.js или index.node , служащий главной точкой входа модуля.

Зачем использовать каталог вместо одного модуля? Чаще всего это делается из-за того, что вы используете существующие библиотеки JavaScript и предоставляете файл — <<обертку>>, который <<упаковывает>> экспортируемые функции командой exports . А может быть, ваша библиотека настолько велика, что вы хотите разбить ее для удобства внесения изменений.

В любом случае следует помнить, что все экспортируемые объекты должны находиться в одном главном файле, загружаемом Node.

Подготовка модуля к публикации

Если вы захотите сделать свой пакет доступным для других, вы можете рекламировать его на своем сайте, но при этом вы упустите значительную аудиторию. Готовые модули лучше публиковать в реестре npm.

Ранее я упоминала о файле package.json. Документацию по JSON для npm можно найти по этому адресу https://docs.npmjs.com/files/package.json. Она базируется на рекомендациях системы модулей CommonJS.

В пакет package.json рекомендуется включать следующие поля:

  • name — имя пакета (обязательно).
  • description — описание пакета.
  • version — текущая версия, соответствующая требованиям семантической версии (обязательно).
  • keywords — массив условий поиска.
  • maintainers — массив ответственных за сопровождение пакета (с именами, адресами электронной почты и сайтами).
  • contributors — массив соавторов пакета (с именами, адресами электронной почты и сайтами).
  • bugs — URL-адрес для отправки ошибок.
  • licenses — массив лицензий.
  • repository — репозиторий пакетов.
  • dependencies — необходимые пакеты и их номера версий.

Обязательны только поля name и version , хотя включить рекомендуется все поля. К счастью, npm упрощает создание этого файла. Если ввести в командной строке следующую команду:

npm init

программа переберет все обязательные/рекомендованные поля, предложив вам ввести значение каждого. Когда все будет сделано, она сгенерирует файл package.json.

Сначала мы создадим в node_modules подкаталог с именем inputcheck и перенесем в него существующий код InputChecker. Файлу необходимо присвоить имя index.js . Затем в код вносятся изменения и из него извлекается часть, реализующая новый объект. Мы сохраним ее для будущего тестового файла.

const util = require('util');
const eventEmitter = require('events').EventEmitter;
const fs = require('fs');
exports.InputChecker = InputChecker;

function InputChecker(name, file) {
    this.name = name;
    this.writeStream = fs.createWriteStream(`./${file}.txt`,
        {'flags' : 'a',
            'encoding' : 'utf8',
            'mode' : 0666
        }
    );
};

util.inherits(InputChecker,eventEmitter);
InputChecker.prototype.check = (input) => {
    const command = input.toString().trim().substr(0,3);
    if (command == 'wr:') {
        this.emit('write', input.substr(3, input.length));
    } else if (command == 'en:') {
        this.emit('end');
    } else {
        this.emit('echo', input);
    }
};

Экспортировать функцию объекта напрямую не удастся, потому что util.inherits ожидает, что в файле с именем InputChecker существует объект. Прототип объекта InputChecker изменяется позднее в файле, также можно было изменить ссылки в коде и использовать exports.InputChecker , но это неуклюжее решение. С таким же успехом объект можно присвоить в отдельной команде.

Чтобы создать файл package.json, я выполнил команду npm init и ответил на все вопросы.

Сгенерированный файл package.json для модуля inputChecker:

{
  "name": "inputcheck",
  "version": "1.0.0",
  "description": "Looks for and implements commands from input",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "command",
    "check"
  ],
  "author": "HackerX.ru",
  "license": "ISC"
}

Команда npm init не запрашивает информацию о зависимостях, поэтому их придется добавить прямо в файл. Впрочем, есть другое, более правильное решение — использовать команду npm install —save при установке модулей, чтобы зависимости были добавлены автоматически. Однако модуль InputChecker не зависит от внешних модулей, поэтому эти поля можно оставить пустыми.

На этой стадии мы можем протестировать новый модуль и убедиться в том, что он действительно работает как модуль. В листинге 3.4 приведен фрагмент предыдущей версии приложения InputChecker, которая тестирует новый объект, теперь выделенный в отдельное тестовое приложение.

Тестовое приложение InputChecker:

const inputChecker = require('inputcheck').InputChecker;
const ic = new inputChecker('Shelley','output');

ic.on('write', (data) =>
  this.writeStream.write(data, 'utf8');
);

ic.addListener('echo', ( data) =>
    console.log(`${this.name} wrote ${data}`);
);

ic.on('end', () => process.exit());

process.stdin.resume();
process.stdin.setEncoding('utf8');
process.stdin.on('data', (input) => ic.check(input));

Теперь тестовое приложение можно переместить в новый подкаталог test в каталоге модуля, чтобы оно было упаковано в модуле как пример. По общепринятым правилам следует предоставить каталог test с одним или несколькими тестовыми приложениями, а также каталог doc с документацией. Для такого маленького модуля файла README должно быть достаточно.

Так как у нас теперь имеется тестовое приложение, необходимо внести изменения в файл package.json и добавить в него ссылку:

"scripts": {
  "test": "node test/test.js"
},

Это довольно примитивный тест, который не использует мощные тестовые возможности Node, но и он показывает, как может работать тестирование. Чтобы запустить тестовое приложение, введите в командной строке следующую команду:

npm test

Остается создать сжатый tar-архив модуля. Впрочем, если вы публикуете модуль так, как описано в разделе «Публикация модуля», этот шаг можно пропустить.

Публикация модуля

Создатели npm также предоставили нам руководство с подробным описанием того, что необходимо сделать для публикации модуля Node: Developer Guide (https://docs.npmjs.com/misc/developers).

В документации приведены дополнительные требования к файлу package.json. В дополнение к уже созданным полям также необходимо добавить поле directories с хешем папок, включая уже упоминавшиеся test и doc:

"directories": {
  "doc" : ".",
  "test" : "test",
  "example" : "examples"
}

Перед публикацией в руководстве рекомендуется протестировать модуль на корректность установки. Чтобы выполнить тестирование, введите следующую команду в корневом каталоге модуля:

npm install . -g

К этому моменту мы протестировали модуль inputChecker, изменили файл package.json, добавили в него каталоги и убедились в том, что пакет успешно устанавливается.

Затем необходимо добавить себя как пользователей npm, если это не было сделано ранее. Введите следующую команду:

npm adduser

после чего по отображаемым подсказкам введите имя пользователя, пароль и адрес электронной почты.

Осталось сделать последний шаг:

npm publish

Можно указать путь к tar-архиву или каталогу. Как предупреждает Guide, доступ предоставляется ко всему содержимому каталога, если только вы не используете в файле package.json директиву .npmignore со списком файлов для игнорирования материала. Тем не менее перед публикацией модуля лучше просто удалить все, без чего можно обойтись.

После публикации — и после того, как исходный код также будет загружен в GitHub (если вы используете этот репозиторий), — модуль официально готов для использования другими разработчиками. Рекламируйте свой модуль в Твиттере, Google+, Facebook, на своем сайте и вообще повсюду, где люди смогут о нем узнать. Такая реклама не хвастовство, а распространение информации.

The post Как создать собственные модули в Node.js и опубликовать в NPM appeared first on HackerX.

]]>
https://hackerx.ru/node-js-npm-module/feed/ 0
Node.js Promise — Использование промисов в серверной JavaScript https://hackerx.ru/node-js-promise/ https://hackerx.ru/node-js-promise/#respond Sat, 19 Aug 2017 08:01:14 +0000 https://hackerx.ru/?p=872 Обратные вызовы являются основой асинхронного программирования на JavaScript и в Node.js, но за прошедшие годы появились альтернативные подходы, позволяющие упростить работу с асинхронным кодом. В этой статье мы рассмотрим самые популярные из таких альтернатив, объекты Promise и генераторы, а также новейший синтаксис async await, который будет введен в JavaScript как часть спецификации ECMAScript 2017. Мы увидим, […]

The post Node.js Promise — Использование промисов в серверной JavaScript appeared first on HackerX.

]]>
Обратные вызовы являются основой асинхронного программирования на JavaScript и в Node.js, но за прошедшие годы появились альтернативные подходы, позволяющие упростить работу с асинхронным кодом.

В этой статье мы рассмотрим самые популярные из таких альтернатив, объекты Promise и генераторы, а также новейший синтаксис async await, который будет введен в JavaScript как часть спецификации ECMAScript 2017.

Мы увидим, как эти альтернативы могут упростить управление асинхронными потоками. И наконец, сравним все эти подходы, выявив плюсы и минусы каждого из них, чтобы иметь возможность разумно подойти к выбору подхода, наилучшим образом соответствующего требованиям проекта на платформе Node.js.

Объект Promise в JavaScript и Node.js

Стиль передачи продолжения (Continuation Passing Style, CPS) не является единственным способом реализации асинхронного кода. В действительности экосистема JavaScript предлагает интересные альтернативы традиционному шаблону обратных вызовов. Одной из самых распространенных таких альтернатив является объект Promise, которому уделяется все больше внимания, особенно сейчас, когда он стал частью спецификации ECMAScript 2015 и обрел встроенную поддержку, начиная с версии 4, платформы Node.js.

Что такое и для чего нужен Promise

Выражаясь простым языком, объект Promise является абстракцией, позволяющей функциям возвращать объект Promise, представляющий конечный результат асинхронной операции. Мы говорим, что объект Promise ожидает, если асинхронная операция еще не завершилась, выполнен – если операция завершилась успешно, и отклонен – если возникла ошибка. После того как объект Promise будет выполнен или отклонен, он считается установившимся.

Чтобы получить результат выполнения или ошибку (причину), вызвавшую отклонение, можно использовать метод then() объекта Promise:

promise.then([onFulfilled], [onRejected])

Здесь onFulflled() – это функция, которой передается результат выполнения асинхронной операции, а onRejected() – функция, которой передается причина отклонения. Обе функции являются необязательными.

Чтобы получить представление, как применение объектов Promise может изменить код, рассмотрим следующий фрагмент кода:

asyncOperation(arg, (err, result) => {
  if(err) {
    //обработка ошибки
  }
  //работа с результатом
});

Объекты Promise позволяют преобразовать этот типичный CPS-­код в более структурированный и элегантный код, например:

asyncOperation(arg)
  .then(result => {
    //работа с результатом
  }, err => {
    //обработка ошибки
  });

Одним из важнейших свойств метода then() является синхронный возврат другого объекта Promise. Если любая из функций – onFulflled() или onRejected() – вернет значение x, метод then() вернет один из следующих объектов Promise:

  • выполненный со значением x, если x является значением;
  • выполненный с объектом x, где x является объектом Promise или thenableобъектом;
  • отклоненный с причиной отклонения x, где x является объектом Promise или thenable­объектом.

 

thenable-объект – это Promise-подобный объект, имеющий метод then(). Этот термин используется для обозначения объекта, фактическая реализация которого отличается от реализации Promise.

Эта особенность позволяет создавать цепочки из объектов Promise, облегчая объединение и компоновку асинхронных операций в различных конфигурациях. Кроме того, если не указывается обработчик onFulflled() или onRejected(), результат или причина отклонения автоматически направляется следующему объекту Promise в цепочке. Это дает возможность, например, автоматически передавать ошибку вдоль всей цепочки, пока она не будет перехвачена обработчиком onRejected(). Составление цепочек объектов Promise делает последовательное выполнение заданий тривиальной операцией:

asyncOperation(arg)
  .then(result1 => {
    //возвращает другой объект Promise
    return asyncOperation(arg2);
  })
  .then(result2 => {
    //возвращает значение
    return 'done';
  })
  .then(undefined, err => {
    // здесь обрабатываются все возникшие в цепочке ошибки
  });

Схема на рисунке иллюстрирует другую точку зрения на работу цепочки объектов Promise:

объект Promise

Другим важным свойством объектов Promise является гарантированный асинхронный вызов функций onFulflled() и onRejected(), даже при синхронном выполнении, как в предыдущем примере, где последняя функция then() в цепочке возвращает строку ‘done’. Такая модель поведения защищает код от непреднамеренного высвобождения Залго, что без дополнительных усилий делает асинхронный код более последовательным и надежным.

А теперь самое интересное: если в обработчике onFulflled() или onRejected() возбудить исключение (оператором throw), возвращаемый методом then() объект Promise автоматически будет отклонен с исключением в качестве причины отказа. Это огромное преимущество перед CPS, потому что исключение автоматически будет передаваться вдоль по цепочке, а это означает, что можно использовать оператор throw.

Исторически сложилось, что существует множество библиотек, реализующих объекты Promise, большинство которых не совместимо друг с другом, что препятствует созданию then­цепочек из объектов Promise, созданных разными библиотеками.

Сообщество JavaScript провело сложную работу по преодолению этого ограничения, в результате была создана спецификация Promises / A+. Эта спецификация детально описывает поведение метода then и служит основой, обеспечивающей возможность взаимодействий между объектами Promise из различных библиотек.


Реализации Promises/A+

Как в JavaScript, так и в Node.js есть несколько библиотек, реализующих спецификацию Promises/A+. Ниже перечислены наиболее популярные из них:

  • Bluebird (https://npmjs.org/package/bluebird);
  • Q (https://npmjs.org/package/q);
  • RSVP (https://npmjs.org/package/rsvp);
  • Vow (https://npmjs.org/package/vow);
  • When.js (https://npmjs.org/package/when);
  • объекты Promise из ES2015.

 

По существу, они отличаются только наборами дополнительных возможностей, не предусмотренных стандартом Promises/A+. Как упоминалось выше, этот стандарт определяет модель поведения метода then() и процедуру разрешения объекта Promise, но не регламентирует других функций, например порядка создания объекта Promise на основе асинхронной функции с обратным вызовом.

В примерах ниже мы будем использовать методы, поддерживаемые объектами Promise стандарта ES2015, поскольку они доступны в Node.js, начиная с версии 4, и не требуют подключения внешних библиотек.

Для справки ниже перечислены методы объектов Promise, определяемые стандартом ES2015.

Конструктор (new Promise(function(resolve, reject) {})): создает новый объект Promise, который разрешается или отклоняется в зависимости от функции, переданной в аргументе. Конструктору можно передать следующие аргументы:

  • resolve(obj): позволяет разрешить объект Promise и вернуть результат obj, если obj является значением. Если obj является другим объектом Promise или thenable­объектом, результатом станет результат выполнения obj;
  • reject(err): отклоняет объект Promise с указанной причиной err. В соответствии с соглашением err должен быть экземпляр Error.

 

Статические методы объекта Promise:

  • Promise.resolve(obj): возвращает новый объект Promise, созданный из thenableобъекта, если obj – thenable­объект, или значение, если obj – значение;
  • Promise.all(iterable): создает объект Promise, который разрешается результатами выполнения, если все элементы итерируемого объекта iterable выполнились, и отклоняется при первом же отклонении любого из элементов. Любой элемент итерируемого объекта может быть объектом Promise, универсальным thenable­объектом или значением;
  • Promise.race(iterable): возвращает объект Promise, разрешаемый или отклоняемый, как только разрешится или будет отклонен хотя бы один из объектов Promise в итерируемом объекте iterable, со значением или причиной этого объекта Promise.

 

Методы экземпляра Promise:

  • promise.then(onFulflled, onRejected): основной метод объекта Promise. Его модель поведения совместима со стандартом Promises/A+, упомянутым выше;
  • promise.catch(onRejected): удобная синтаксическая конструкция, заменяющая promise.then(undefned, onRejected).

 

Стоит отметить, что некоторые реализации предлагают другой асинхронный механизм – механизм отложенных вычислений. Мы не будем рассматривать его, поскольку он не является частью стандарта ES2015.

Перевод функций в стиле Node.js на использование объектов Promise

В JavaScript не все асинхронные функции и библиотеки поддерживают объекты Promise изначально. Обычно типичные функции, основанные на обратных вызовах, требуется преобразовать так, чтобы они возвращали объекты Promise. Этот процесс называется переводом на использование объектов Promise.

К счастью, соглашения об обратных вызовах, используемые на платформе Node.js, позволяют создавать функции, способные переводить любые функции в стиле Node.js на использование объектов Promise. Это несложно осуществить с помощью конструктора объекта Promise. Создадим новую функцию promisify() и добавим ее в модуль utilities.js (чтобы ее можно было использовать в приложении веб­паука):

module.exports.promisify = function(callbackBasedApi) {
  return function promisified() {
    const args = [].slice.call(arguments);
    return new Promise((resolve, reject) => {  //[1]
      args.push((err, result) => {             //[2]
        if(err) {
          return reject(err);                  //[3]
        }
        if(arguments.length <= 2) {            //[4]
          resolve(result);
        } else {
          resolve([].slice.call(arguments, 1));
        }
     });
     callbackBasedApi.apply(null, args);      //[5]
   });
 }
};

Приведенная выше функция возвращает другую функцию – promisifed(), которая является версией callbackBasedApi, возвращающей объект Promise. Вот как она работает:

  1. функция promisifed() создает новый объект с помощью конструктора Promise и немедленно возвращает его;
  2. в функции, что передается конструктору Promise, мы передаем специальную функцию обратного вызова для вызова из callbackBasedApi. Поскольку функция обратного вызова всегда передается в последнем аргументе, мы просто добавляем ее в список аргументов (args) функции promisifed();
  3. если специальная функция обратного вызова получит ошибку, объект Promise немедленно отклоняется;
  4. в случае отсутствия ошибки осуществляется разрешение объекта Promise со значением или массивом значений, в зависимости от количества результатов, переданных функции обратного вызова;
  5. в заключение вызывается callbackBasedApi с созданным списком аргументов.

 

Большинство реализаций поддерживает вспомогательный метод преобразования типичных функций в стиле Node.js в функции, возвращающие объекты Promise. Например, библиотека Q содержит функции Q.denodeify() и Q.nbind(), библиотека Bluebird имеет Promise.promisify(), а When.js содержит node.lift().

Последовательное выполнение Промисов

Теперь, после знакомства с теорией, можно приступать к созданию приложений. Рассмотрим работу на примере создание веб-паука:

Код, который представлен ниже, не будет работать. Это просто пример использование.

const utilities = require('./utilities');
const request = utilities.promisify(require('request'));
const mkdirp = utilities.promisify(require('mkdirp'));
const fs = require('fs');
const readFile = utilities.promisify(fs.readFile);
const writeFile = utilities.promisify(fs.writeFile);

function download(url, filename) {
  console.log(`Downloading ${url}`);
  let body;
  return request(url)
    .then(response => {
      body = response.body;
      return mkdirp(path.dirname(filename));
    })
    .then(() => writeFile(filename, body))
    .then(() => {
      console.log(`Downloaded and saved: ${url}`);
      return body;
    });
}

Promise: Последовательные итерации

На данный момент, на примере приложения веб­-паука, мы рассмотрели объекты Promise и приемы их использования для создания простой элегантной реализации последовательного потока выполнения. Но этот код обеспечивает выполнение лишь известного заранее набора асинхронных операций. Поэтому, чтобы восполнить пробелы в исследовании последовательного выполнения, нам нужно разработать фрагмент, реализующий итерации с помощью объектов Promise. И снова прекрасным примером для демонстрации станет функция spiderLinks().

function spiderLinks(currentUrl, body, nesting) {
  let promise = Promise.resolve();
  if(nesting === 0) {
    return promise;
  }
  const links = utilities.getPageLinks(currentUrl, body);
  links.forEach(link => {
    promise = promise.then(() => spider(link, nesting – 1));
  });
  return promise;
}

Для асинхронного обхода всех ссылок на веб-­странице нужно динамически создать цепочку объектов Promise.

  1. Начнем с определения «пустого» объекта Promise, разрешаемого как undefned. Он будет служить началом цепочки.
  2. Затем в цикле присвоим переменной promise новый объект Promise, полученный вызовом метода then() предыдущего объекта Promise в цепочке. Это и есть шаблон асинхронных итераций с использованием объектов Promise.

 

В конце цикла переменная promise будет содержать объект Promise, который вернул последний вызов then() в цикле, поэтому он будет разрешен после разрешения всех объектов Promise в цепочке.

The post Node.js Promise — Использование промисов в серверной JavaScript appeared first on HackerX.

]]>
https://hackerx.ru/node-js-promise/feed/ 0
Node.js: Паттерны / шаблоны проектирования https://hackerx.ru/node-js-shabloni-proektirovanie/ https://hackerx.ru/node-js-shabloni-proektirovanie/#respond Fri, 18 Aug 2017 13:43:46 +0000 https://hackerx.ru/?p=868 Освоение асинхронной природы платформы Node.js, вообще говоря, не тривиальная задача, особенно для тех, кто переходит на нее с таких языков, как PHP, где обычно не приходится иметь дело с асинхронным кодом. В синхронном программировании используется привычная концепция, представляющая код как ряд последовательных вычислений, направленных на решение конкретной задачи. Любая операция является блокирующей, поскольку только после […]

The post Node.js: Паттерны / шаблоны проектирования appeared first on HackerX.

]]>
Освоение асинхронной природы платформы Node.js, вообще говоря, не тривиальная задача, особенно для тех, кто переходит на нее с таких языков, как PHP, где обычно не приходится иметь дело с асинхронным кодом.

В синхронном программировании используется привычная концепция, представляющая код как ряд последовательных вычислений, направленных на решение конкретной задачи. Любая операция является блокирующей, поскольку только после ее завершения можно переходить к выполнению следующей. Такой подход упрощает понимание и отладку кода.

Напротив, в асинхронном программировании некоторые операции, например чтение файла или сетевой запрос, могут выполняться в фоновом режиме. После вызова асинхронной операции следующая операция выполняется немедленно, даже если предыдущая операция еще не закончила выполняться. Операции в фоновом режиме могут закончить свое выполнение в любое время, и все приложение должно быть реализовано так, чтобы должным образом отреагировать на завершение асинхронного вызова.

Хотя этот неблокирующий подход практически всегда гарантирует более высокую производительность, по сравнению с всегда блокирующим сценарием, он привносит трудную для восприятия парадигму, которая может стать весьма громоздкой в больших приложениях, требующих сложного управления потоками.



Платформа Node.js предлагает ряд инструментов и шаблонов проектирования для разработки оптимального асинхронного кода. Важно освоить их, чтобы уверенно ими пользоваться для создания производительных приложений, простых для понимания и отладки.

В следующей статье начнём знакомиться с двумя важных шаблонов асинхронной обработки: Callback (Обратный вызов) и Event Emitter (Генератор событий).

The post Node.js: Паттерны / шаблоны проектирования appeared first on HackerX.

]]>
https://hackerx.ru/node-js-shabloni-proektirovanie/feed/ 0