Новые возможности io.js, которые Вы возможно не используете

от автора

Оригинал: New io.js Features You May Not Be Using

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

Если Вы не следили за развитием io.js, ничего страшного — в данной статье мы вкратце представим основные возможности платформы. Рассматривать их мы будет по мере выхода, то есть от старых к новым. Где это будет нужным, дадим ссылки на соответствующую документацию (на английском языке). Описывая каждую новую функциональность, будем указывать ее первую версию. Код написан с использованием стандартных функций ES6, которые доступны в io.js. Итак, начнем…

ES6 возможности (1.0.0)

Первоначально одной из задач разработчиков io.js было приблизиться к функциональности V8, а именно: полноценно использовать все имеющиеся возможности ES6. Считалось, что встроенные по умолчанию генераторы, так же, как и другие функции ES6, будут работать достаточно стабильно и без флагов. Советуем не спешить с поиском информации по ES6 — для начала ознакомьтесь с документацией, ссылки на которую мы дадим в статье.

Ссылка на документацию: Функции ES6

Отметим: По умолчанию в Node 0.12 присутствуют некоторые функции ES6. Под флагом —harmony можно найти еще больше функций. Однако, работа и доступность функций ES6 отличается от io.js (например: в Node генераторы по умолчанию не присутствуют).

Подробная документация по ошибкам (1.2.0)

Когда-нибудь задавались вопросом, что такое EPIPE, EMFILE, ENOENT? Я лично задавал себе этот вопрос и не раз. Слава богу, теперь в io.js появилась значительно улучшенная документация по ошибкам.

Ссылка на документацию: Документация по ошибкам

Простая реализация потоков (1.2.0)

Формально, когда необходимо применить поток, то Вы расширяете базовый поток и применяете один или несколько методов, в зависимости от типа потока. Например, поток Transform предполагает использование метода _transform и метода _flush опционально. На примере ниже видно, как поток Stream разбивает файл по строкам:

var stream = require('stream') var liner = new stream.Transform( { objectMode: true } )   liner._transform = function (chunk, enc, done) {      var data = chunk.toString()      if (this._lastLineData) {        data = this._lastLineData + data      }        var lines = data.split('\n')      this._lastLineData =        lines.splice(lines.length-1,1)[0]        lines.forEach(this.push.bind(this))      done() }   liner._flush = function (done) {      if (this._lastLineData) {        this.push(this._lastLineData)      }      this._lastLineData = null      done() }   module.exports = liner 

Со всеми “кишками” метода наружу код выглядит довольно неопрятно. Теперь Вы можете передать эти методы в качестве опций в конструктор. Просто уберите знак нижнего подчеркивания (_). Liner позволяет изменить код (с использованием нотации объекта из расширений в ES6) и получить следующее:

'use strict' const stream = require('stream')   let liner = new stream.Transform({   // Include any existing constructor options   objectMode: true,     // This is the _transform method   transform (chunk, enc, done) {     let data = chunk.toString()       if (this._lastLineData) {       data = this._lastLineData + data     }       let lines = data.split('\n')     this._lastLineData =       lines.splice(lines.length - 1, 1)[0]       lines.forEach(this.push.bind(this))     done()   },     // This is the _flush method   flush (done) {     if (this._lastLineData) {       this.push(this._lastLineData)     }     this._lastLineData = null     done()   } })   module.exports = liner 

Ссылка на документацию: Конструктор потока

Возможность просмотра всех IP адресов для домена (1.2.0)

Если бы Вы прописали команду dns.lookup в ранних версиях io.js, то Вам бы выдали только первый адрес. Сейчас же есть опция {all: true}, которая позволяет получить целый массив адресов.

'use strict' const dns = require('dns')   // Returns first address dns.lookup('google.com', console.log) // => '173.194.46.40' 4   // Returns all resolved addresses in an array dns.lookup('google.com', { all: true }, console.log) /* => [ { address: '173.194.46.40', family: 4 },   { address: '173.194.46.38', family: 4 },   ...   { address: '2607:f8b0:4009:804::1007', family: 6 } ] */ 

Ссылка на документацию: О dns.lookup

Событие unhandleRejection (1.4.1)

Если отклонить(reject) promise, но об этом никто никогда не узнает, можно ли считать, что его действительно отклонили? Конечно это произошло, но опять же — об этом никто не узнает! Как можно догадаться, здесь таится корень появления множества сложных ошибок в коде. Для примера обратите внимание на код ниже:

'use strict' let delay = function (ms) {   return new Promise(function (resolve) {     setTimeout(resolve, ms)   }) }   delay(2000)   .then(function (data) {     data.foo = 'hello'   }) 

Видите ошибку? Функция delay возвращает promise, который будет выполнен через определенное время, а когда он будет выполнен, получим undefined и ReferenceError. Это произойдет, потому что мы попытались получить доступ к свойству foo со значением undefined. Между тем, мы никогда не узнаем, что произошло, и будем с удивлением чесать в затылке, потому что на необработанные отказы никто не обратил внимание. Хотя в некоторых библиотеках, возможность такого поведения promise прописана, в ES6 Вы информации об этом не найдете. К счастью, Вы можете провести проверку кода с помощью события unhandledRejection через process.

process.on('unhandledRejection', function (er) {   console.log('got unhandled rejection', er.stack) }) 

Если Вы используете promise в ES6, то рекомендуем настроить unhandledRejection, чтобы ни один отказ не остался незамеченным.

Ссылка на документацию: process.on(“unhandledRejection”)

Отметим: Также существует событие rejectionHandled. Оно используется в том случае, когда надо разобраться с отказом promise, возникающим в следующем шаге event loop. rejectionHandled полезен, когда необходимо обнулить promise, которые были неверно отсеяны с помощью unhandledRejection. Для более детального описания смотрите документацию.

StreamWrap и JSStream (1.4.1)

Начиная с данной версии, между потоками в C++ и JS появилась полноценная связь. Теперь Вы можете использовать стандартный Duplex поток для ввода данных при работе с потоками низкого порядка (например, c программными гнездами) на C++. Метод tls.connect () использует эту особенность в полной мере. В качестве примера просмотрите следующий набор тестов.

Метод Buffer#indexOf

Далее описан удобный метод того, как проводить поиск в буфере с помощью строки, буфера или числа. Метод ведет себя так же, как и Array#indexOf, а именно: он возвращает индекс стартовой позиции первого найденного совпадения в буфере. По желанию вы можете задать стартовый индекс в качестве дополнительного параметра.

'use strict' const assert = require('assert') let buf = new Buffer('abc def ghi')   assert.equal(buf.indexOf('abc'), 0) assert.equal(buf.indexOf('bc'), 1) assert.equal(buf.indexOf('def'), 4) assert.equal(buf.indexOf('c'), 2) assert.equal(buf.indexOf('c', 4), 11) 

Дополнительный метод lastIndexOf пока находится в обсуждении.

Ссылка на документацию: buffer#indexOf

Модули предварительной загрузки (1.6.0)

Теперь Вы можете предварительно загрузить модули во время выполнения скриптов или использования REPL. Сделать это можно с помощью -r или флага —require. Например:

iojs -r ./foo -r bar my-app.js 

То же самое, что и:

require('./foo') require('bar') require('./my-app') 

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

if (cfg.useHeapdump) require('heapdump') 

Вам надо будет всего лишь запустить приложение с предварительно загруженным модулем тогда, когда Вам нужна требуемая функциональность:

iojs -r heapdump app.js 

Еще один вариант использования — вместе с компиляторами (Babel, CoffeeScript и т.п.). Например, если Вы используете Babel для компиляции кода на ES6 или ES7, необходимо прописать примерно следующее:

require('babel/register') require('./my-actual-app') 

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

iojs -r babel/register my-actual-app.js 

Отметим: На настоящий момент, Babel уже полноценно поддерживает Node. Специальный инструмент позволяет делать описанное выше и даже больше.

Устранение ошибок с помощью Synchronous I/O (2.1.0)

Хотя Synchonous I/O удобен, в особенности для shell-скриптинга, от него сильно снижается производительность многих приложений (например, серверов). Вы можете поискать Sync в коде, однако что делать, если Вы используете сторонний модуль, который не следует схеме именования? Именно здесь на выручку приходит флаг —trace-sync-io. Когда выполняется синхронный запрос, Вам приходит уведомление о stack trace.

Давайте посмотрим на простой пример:

'use strict' const http = require('http') const cp = require('child_process')   http.createServer(function (req, res) {   let stdout = cp.execFileSync('whoami')   res.end(`${stdout}\n`) }).listen(3000) 

Имеем HTTP сервер, который обрабатывает синхронный код по каждому запросу. Рекомендовать такой вариант нельзя. Так, если мы выполним iojs —trace-sync-io server.js, а затем перейдем на httpL//localhost:3000, увидим в консоли следующее предупреждение:

WARNING: Detected use of sync API     at spawnSync (child_process.js:1241:27)     at execFileSync (child_process.js:1291:13)     at /Users/wavded/Projects/whats-new-iojs/server.js:6:19     at emitTwo (events.js:87:13)     at emit (events.js:172:7)     at parserOnIncoming (_http_server.js:474:12)     at parserOnHeadersComplete (_http_common.js:88:23)     at socketOnData (_http_server.js:325:22)     at emitOne (events.js:77:13) 

Всего понемногу

Несколько интересных возможностей, на которые стоит обратить внимание:

  1. Вы можете прописать require (‘./’) с помощью require (‘.’) (1.6.2).
  2. При использовании console.log или util.inspect, ES6 объекты Promise, Map и Set имеют красивый вид (2.0.0).
  3. os.tmpdir () работает одинаково хорошо на всех операционных системах (2.0.0). Ранее, некоторые операционные системы выдавали косые слэши, не говоря уже о других ошибках. Теперь Вы никогда не столкнетесь с этой проблемой.
  4. Множество других улучшений: парсинг строки запроса(query string) (1.6.1), меньшее использование tls памяти (2.0.0), более быстрый process.nextTick (2.0.0) и util.format для отдельных аргументов (2.1.0).
  5. Постепенное улучшение безопасности io.js. При обмене ключами по методу Диффи-Хеллмана, параметры должны быть не менее 1024 бит (2.1.0).

Где найти больше информации?

По моему мнению лучшую информацию можно найти на GitHub в ChangeLog. Также io.js ведет официальный блог на Medium, на котором можно найти информацию о последних обновлениях платформы и о проекте в целом.

Автор: Марк Хартер (Marc Harter)
Над переводом работали: greebn9k(Сергей Грибняк), Роман Сенин, Андрей Хахарев
Singree

ссылка на оригинал статьи http://habrahabr.ru/post/260573/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *