Util.promisify() в Node.js

Если вы когда-нибудь работали с Javascript, вы, наверное, сталкивались с обратными вызовами. Javascript известен своей встроенной асинхронной философией. Обратные вызовы присутствуют повсюду: от стандартных встроенных модулей до других фреймворков и библиотек. Но у обратных вызовов есть и тёмная сторона.

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

Для таких обещаний существует ряд хороших библиотек, например, Bluebird и Q. Но встроенные модули и множество других библиотек их не используют. Хотя эти библиотеки способны преобразовывать традиционные методы обратного вызова в обещания, у нас есть официальный способ обещать методы обратного вызова в Node v8. Это util.promisify. Согласно документация Node.js:

util.promisify выполняет функцию, следующую общему стилю обратного вызова Node.js, т.е. принимает a (err, value) => … обратный вызов в качестве последнего аргумента и возвращает версию, которая возвращает обещания.

Посмотрим на пример:

const fs = require('fs');
fs.readFile('./index.js', 'utf8', (err, text) => {
    if (err) {
        console.log('Error', err);
    } else {
        console.log(text);
    }
});

Этот пример с обещаниями может выглядеть так:

const fs = require('fs');
const util = require('util');
const readFile = util.promisify(fs.readFile);
readFile('./index.js', 'utf8')
    .then((text) => {
        console.log(text);
    })
    .catch((err) => {
        console.log('Error', err);
    });

Здесь мы использовали util.promisify, чтобы преобразовать файл fs.ReadFile в метод, основанный на обещаниях. Теперь вместо обратного вызова метод ReadFile даёт обещание. У обещаний есть два метода: then и catch.then. Они используется для получения результата, если вызов функции был успешным. catch используется для обнаружения ошибки, если она произошла. Преимущество обещаний в том, что мы можем связывать асинхронные вызовы, не попадая в ад обратного вызова.

Асинхронность и ожидание

Самая весёлая часть. С обещаниями намного проще работать в сочетании с ключевыми словами async и await. Даже цепочка обещаний может выглядеть отвратительно, когда она становится больше. Асинхронность и ожидание делают его более чистым. Вот приведённый выше пример с асинхронностью и ожиданием:

const fs = require('fs');
const util = require('util');
const readFile = util.promisify(fs.readFile);
async function doFile() {
    try {
        const text = await readFile('./index.js', 'utf8');
        console.log(text);
    } catch (err) {
        console.log('Error', err);
    }
}
doFile();

Ответить