Нові можливості 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 method _transform
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 method _flush
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

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.