Skip to content
Tags

Комбо-библиотека Do

28/04/2010

При использовании асинхронных функций в Node.js программист часто сталкивается с однотипными задачами, красивое решение к которым на первый взгляд найти не очень просто. Несколько примеров:

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

К счастью для нас, Github-пользователь creationix написал удобную библиотеку, которая умеет делать всё вышеперечисленное и кое что ещё.

Скачать Do можно с Github. Я не буду описывать установку, она не отличается от любого другого модуля для Node. Я просто рассмотрю её основные применения. Но сначала — пару слов о continuables.

Continuables

Do использует синтаксис асинхронных функций, несколько отличающийся от традиционного синтаксиса node.js: continuables. Вместо вот такой конструкции:

var fs = require('fs');
var sys = require('sys');

fs.readdir("/usr", function (err, files) {
  if (err) throw err;
  sys.puts("/usr files: " + files);
});

…при continuable-стиле из асинхронной функции и параметров создаётся новая функция. Эта функция принимает в качестве параметров callback и errback (который будет выполнен в случае неудачного завершения асинхронной операции):

fs.readdir("/usr")(function (files) {
  sys.puts("/usr files: " + files);

}, function (err) {
  throw err;

});

Это делает код несколько короче (мы избавляемся от проверки err), и позволяет передавать в качестве callback`а стороннюю функцию — например, при чтении файла мы можем передать сразу sys.puts — и файл сразу будет выведен в консоль:

var ourfile = readfile('file.txt');

ourfile(sys.puts, function() { sys.puts('Error reading file') });

Такой синтаксис позволяет несколько проще обращаться с несколькими асинхронными функциями сразу. Do также умеет преобразовывать обычные асинхронные функции в continuable-стиль, так что её удобно использовать с другими библиотеками.

Ожидание нескольких асинхронных функций

Всё таки, как именно Do облегчает написание асинхронного кода? Возьмём простой пример — нам надо дождаться нескольких разных событий. К примеру, мы открываем одновременно несколько соединений — к базе и HTTP-серверу. В Do для этого есть функция Do.parallel:

// Несколько аргументов
Do.parallel(
  Do.read("/etc/passwd"),
  Do.read(__filename)
)(function (passwd, self) {
  // Сделать что нибудь
}, errorHandler);

// Один аргумент
// Single argument
var actions = [
  Do.read("/etc/passwd"),
  Do.read(__filename)
];
Do.parallel(actions)(function (results) {
  // Do something
}, errorHandler);

Do.parallel удобно применять когда функции должны быть разными (для применения одной функции к разным значениям есть другой метод), но в качестве примера вполне подойдёт. Здесь мы ждём открытия двух файлов. В качестве аргументов Do.parallel можно передавать функции либо массив функций. В первом случае результаты будут переданы отдельными параметрами, во втором — в виде массива.

Выполнение событий по цепочке

Функция Do.chain принимает несколько действий, и выполняет их по очереди, передавая результат текущего действия в качестве аргумента следующему:

// Несколько аргументов
Do.chain(
  Do.read(__filename),
  function (text) {
    return Do.save("newfile", text);
  },
  function () {
    return Do.stat("newfile");
  }
)(function (stat) {
  // Сделать что нибудь
}, errorHandler);

// Один аргумент
var actions = [
  Do.read(__filename),
  function (text) {
    return Do.save("newfile", text);
  },
  function () {
    return Do.stat("newfile");
  }
];
Do.chain(actions)(function (stat) {
  // Сделать что нибудь
}, errorHandler);

Эта функция помогает избегать глубокой вложенности кода (Node.js страдает этим когда в обработке одних данных задействовано несколько асинхронных функций).

Асинхронная обработка массивов

Ещё одна часто встречающаяся задача — вызвать асинхронный обработчик для нескольких элементов массива и получить массив результатов. Самый простой пример — получить список записей из базы данных или прочитать несколько файлов. На входе у нас — массив имён файлов, на выходе — массив содержимого файлов. Do.map позволяет это сделать без труда:

// Прямая передача обработчика
var files = ['users.json', 'pages.json', 'products.json'];
function loadFile(filename, callback, errback) {
  fs.read(filename)(function (data) {
    callback([filename, data]);
  }, errback);
}
Do.map(files, loadFile)(function (contents) {
  // Сделать что нибудь
}, errorHandler);

// Передача в стиле continuable
var files = ['users.json', 'pages.json', 'products.json'];
Do.map(files, fs.read)(function (contents) {
  // Сделать что нибудь
}, errorHandler);

Другие возможности библиотеки

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

  • Do.filter: применяет функцию-фильтр к массиву значений и возвращает массив элементов, для которых фильтр вернул true
  • Do.filterMap: комбинация Do.filter и Do.map — для каждого элемента выполняется асинхронный обработчик, но те элементы для которых он вернул undefined не попадают в массив результатов
  • Do.convert: преобразовывает асинхронную функцию со стандартным синтаксисом в асинхронную функцию в стиле continuable

Ссылки по теме

2 комментария

Trackbacks & Pingbacks

  1. Комбо-библиотека Do « nodeJS
  2. progg.ru

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

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s

%d такие блоггеры, как: