Оригинал: 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)
Всего понемногу
Несколько интересных возможностей, на которые стоит обратить внимание:
- Вы можете прописать require (‘./’) с помощью require (‘.’) (1.6.2).
- При использовании console.log или util.inspect, ES6 объекты Promise, Map и Set имеют красивый вид (2.0.0).
- os.tmpdir () работает одинаково хорошо на всех операционных системах (2.0.0). Ранее, некоторые операционные системы выдавали косые слэши, не говоря уже о других ошибках. Теперь Вы никогда не столкнетесь с этой проблемой.
- Множество других улучшений: парсинг строки запроса(query string) (1.6.1), меньшее использование tls памяти (2.0.0), более быстрый process.nextTick (2.0.0) и util.format для отдельных аргументов (2.1.0).
- Постепенное улучшение безопасности io.js. При обмене ключами по методу Диффи-Хеллмана, параметры должны быть не менее 1024 бит (2.1.0).
Где найти больше информации?
По моему мнению лучшую информацию можно найти на GitHub в ChangeLog. Также io.js ведет официальный блог на Medium, на котором можно найти информацию о последних обновлениях платформы и о проекте в целом.
Автор: Марк Хартер (Marc Harter)
Над переводом работали: greebn9k(Сергей Грибняк), Роман Сенин, Андрей Хахарев
Singree
ссылка на оригинал статьи http://habrahabr.ru/post/260573/
Добавить комментарий