Рубрики
Без рубрики

Преобразование обратных вызовов на обещания в Node.js

Asynchronous JavaScript Highty используются обратные вызовы, но теперь используйте обещания, так как легче управлять. В этой статье мы конвертируем обратные вызовы для обещаний.

Автор оригинала: Janith Kasun.

Вступление

Несколько лет назад обратные вызовы были единственным способом достижения асинхронного выполнения кода в JavaScript. Было мало проблем с обратными вызовами, а самым заметным было «обратный ад».

С ES6, Обещания были введены как решение этих проблем. И, наконец, Async/await Ключевые слова были введены для еще более приятного опыта и улучшенной читаемости.

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

Что такое обратный вызов

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

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

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

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

С этой целью мы будем использовать текстовый файл под названием образец. atxt , содержащий следующее:

Hello world from sample.txt

Тогда давайте напишем простой сценарий Node.js, чтобы прочитать файл:

const fs = require('fs');

fs.readFile('./sample.txt', 'utf-8', (err, data) => {
    if (err) {
        // Handle error
        console.error(err);
          return;
    }

    // Data is string do something with it
    console.log(data);
});

for (let i = 0; i < 10; i++) {
    console.log(i);
}

Запуск этого кода должен давать:

0
...
8
9
Hello world from sample.txt

Если вы запустите этот код, вы должны увидеть 0..9 быть напечатанным до выполненного обратного вызова. Это из-за асинхронного управления JavaScript, о котором мы говорили ранее. Обратный вызов, который регистрирует содержимое файла, будет вызываться только после чтения файла.

В качестве бокового примечания обратные вызовы могут быть использованы в синхронных методах. Например, Array.sort () Принимает функцию обратного вызова, которая позволяет настроить, как элементы отсортированы.

Функции, которые принимают обратные вызовы, называются Функции высшего порядка Отказ

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

Что такое обещание

Обещания были введены с Ecmascript 2015 (Обычно известный как ES6 ) для улучшения опыта разработчика с асинхронным программированием. Как предполагает его имя, это Обещание что объект JavaScript в конечном итоге вернет ценность или Ошибка . Отказ

Обещание имеет 3 государства:

  • В ожидании : Начальное состояние, указывающее на то, что асинхронная операция не завершена.
  • Выполнено Это означает, что асинхронная операция успешно завершена.
  • Отклонено Это означает, что асинхронная операция не удалась.

Большинство обещаний в конечном итоге выглядят так:

someAsynchronousFunction()
    .then(data => {
        // After promise is fulfilled
        console.log(data);
    })
    .catch(err => {
        // If promise is rejected
        console.error(err);
    });

Обещания важны в современном JavaScript, так как они используются с Async/await Ключевые слова, которые были введены в Ecmascript 2016 Отказ С Async/await нам не нужно использовать обратные вызовы или тогда () и поймать () написать асинхронный код.

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

try {
    const data = await someAsynchronousFunction();
} catch(err) {
    // If promise is rejected
    console.error(err);
}

Это похоже на «регулярный» синхронный JavaScript! Вы можете узнать больше о Async/await В нашей статье Node.js async ждет es7 Отказ

Наиболее популярные библиотеки JavaScript и новые проекты используют обещания с Async/await ключевые слова.

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

Давайте посмотрим на пару методов для преобразования обратных вызовов на обещания!

Преобразование обратного вызова к обещанию

Node.js oomisify

Большинство асинхронных функций, которые принимают обратный вызов в Node.js, такие как ФС (Файловая система) Модуль, иметь стандартный стиль реализации – обратный вызов пропускается как последний параметр.

Например, вот как вы можете прочитать файл, используя Fs.readfile () не указав текстовое кодирование:

fs.readFile('./sample.txt', (err, data) => {
    if (err) {
        console.error(err);
          return;
    }

    // Data is a buffer
    console.log(data);
});

Примечание : Если вы укажете UTF-8 Как кодировка вы получите строковый вывод. Если вы не укажете кодировку, вы получите Буфер выход.

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

Если функция, которую вам нужно скрыть для обещания, следует за этими правилами, вы можете использовать Util.promisify , родной модуль Node.js, который покрывает обратные вызовы для обещаний.

Для того, чтобы сделать это, сначала импортируйте Util модуль:

const util = require('util');

Тогда вы используете похищать Метод преобразовать его в обещание:

const fs = require('fs');
const readFile = util.promisify(fs.readFile);

Теперь используйте вновь созданную функцию в качестве регулярного обещания:

readFile('./sample.txt', 'utf-8')
    .then(data => {
        console.log(data);
    })
    .catch(err => {
        console.log(err);
    });

В качестве альтернативы вы можете использовать Async/await Ключевые слова, указанные в следующем примере:

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

const readFile = util.promisify(fs.readFile);

(async () => {
    try {
        const content = await readFile('./sample.txt', 'utf-8');
        console.log(content);
    } catch (err) {
        console.error(err);
    }
})();

Вы можете использовать только ждать Ключевое слово внутри функции, создаваемой с async , следовательно, почему у нас в этом примере есть функциональная обертка. Эта функция обертка также известна как Сразу вызывало функционирование выражений Отказ

Если ваш обратный вызов не следит за этим конкретным стандартом, не волнуйтесь. Util.promisify () Функция может позволить вам настроить Как происходит конверсия.

Примечание : Обещания стали популярными вскоре после того, как они были введены. Node.js уже преобразовал большинство, если не все, его основные функции от обратного вызова к API на основе обещания.

Если вам нужно работать с файлами, использующими обещания, используйте Библиотека, которая поставляется с Node.js Отказ

До сих пор вы узнали, как скрыть unode.js Стандартный стиль обратных вызовов для обещаний. Этот модуль доступен только на Node.js с версии 8. Если вы работаете в браузере или более ранней версии узла, он, вероятно, будет лучше для вас создать свою собственную версию функции на основе обещаний.

Создание вашего обещания

Давайте поговорим о том, как преобразовать обратные вызовы на обещания Util.promisify () Функция недоступна.

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

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

const fs = require('fs');

const readFile = (fileName, encoding) => {
    return new Promise((resolve, reject) => {
        fs.readFile(fileName, encoding, (err, data) => {
            if (err) {
                return reject(err);
            }

            resolve(data);
        });
    });
}

readFile('./sample.txt')
    .then(data => {
        console.log(data);
    })
    .catch(err => {
        console.log(err);
    });

Наша новая функция readfile () Принимает два аргумента, которые мы использовали для чтения файлов с Fs.readfile () Отказ Затем мы создаем новый Обещание Объект, который обернутся над функцией, который принимает обратный вызов, в этом случае Fs.readfile () Отказ

Вместо того, чтобы вернуть ошибку, мы Отклонить обещание. Вместо немедленно ввесть данные, мы решить обещание. Затем мы используем наше обещание readfile () функция как раньше.

Давайте попробуем другую функцию, которая принимает динамическое количество параметров:

const getMaxCustom = (callback, ...args) => {
    let max = -Infinity;

    for (let i of args) {
        if (i > max) {
            max = i;
        }
    }

    callback(max);
}

getMaxCustom((max) => { console.log('Max is ' + max) }, 10, 2, 23, 1, 111, 20);

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

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

Наша обрывная версия выглядит так:

const getMaxPromise = (...args) => {
    return new Promise((resolve) => {
        getMaxCustom((max) => {
            resolve(max);
        }, ...args);
    });
}

getMaxCustom(10, 2, 23, 1, 111, 20)
    .then(max => console.log(max));

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

Заключение

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

В этой статье вы впервые увидели, как использовать Utils.promisfy () Способ в Node.js для преобразования функций, которые принимают обратные вызовы в обещания. Затем вы видели, как создать свой собственный Обещание Объект, который обернутся вокруг функции, которая принимает обратный вызов без использования внешних библиотек.

При этом множество устаревших JavaScript Code может быть легко смешивается с более современными кодовыми базами и практикой! Как всегда, исходный код доступен на Github Отказ