Подтвердить что ты не робот

Node.js модули: Async vs Fibers.promise vs Q_oper8

Просто интересно, может ли кто-нибудь дать мне сравнение компромиссов между этими модулями для обработки асинхронных событий. В частности, мне интересно узнать о причинах использования Async вместо Fibers.promise, который я использую довольно широко, по крайней мере, в своем тестовом коде прямо сейчас. В частности, один из главных плюсов, которые я вижу в Fibers.promise, заключается в том, что я могу поддерживать бифуркацию в цепочке стека, что позволяет использовать try { } catch { } finally, а также позволяет мне гарантировать, что после того, как запрос обработан, ответ завершено.

Кто-нибудь использует Q_oper8? Я нашел это на другой странице и просто задавался вопросом, было ли это уже мертвым или если что-то я должен проверить.

4b9b3361

Ответ 1

Я никогда не слышал о Q_oper8, поэтому я не могу прокомментировать это, но я приду к этому с другого направления. Я слышал об асинхронных первых и Fiber (и его вспомогательных библиотеках) во-вторых, и мне это совсем не нравится.

Недостатки волокна

Непонимание других разработчиков Javascript

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

Это может не иметь значения для вас, но если вам нужно работать в команде, вам придется учить концепцию своим членам (или надеяться, что они имеют опыт работы с концепцией с других языков, например Go).

Поддержка Windows

Итак, чтобы использовать Fiber или любую из библиотек, написанных поверх него, вам сначала нужно сначала скомпилировать его для своей платформы. Я не использую Windows, но обратите внимание, что Fiber не поддерживается в Windows, поэтому ограничивает использование вашей собственной библиотеки вне игры. Это означает, что вы не будете находить библиотеки общего назначения Node.js, написанные в Fiber вообще (и вы, вероятно, не имели бы, так или иначе, так как он добавляет дорогостоящий шаг компиляции, который вам в противном случае удалось бы избежать с помощью async).

Браузер Несовместимый

Это означает, что любой код, который вы пишете с помощью Fiber, не сможет работать в браузере, потому что вы не можете смешивать собственный код с браузером (и я бы не хотел, чтобы пользователь браузера), даже если все, что вы пишете это "Javascript" (это синтаксически Javascript, но семантически нет).

Более сложная отладка

В то время как "обратный ад" может быть менее визуально приятным, в стиле Continuation-Passing Style есть одна очень хорошая вещь для него по сравнению с Co-Routines - вы точно знаете, где возникла проблема из стека вызовов и может отслеживать назад, Co-Routines вводят функцию в более чем одной точке программы и могут выйти из трех видов вызовов: return, throw и yield(), где последняя также является точкой возврата.

С совместными подпрограммами вы выполняете кросс-исполнение между двумя или несколькими функциями, запущенными "одновременно", и вы можете иметь более одного набора совлокальных подпрограмм, запущенных одновременно в цикле событий. С традиционными обратными вызовами гарантируется, что внешняя область функции статична во время выполнения указанной функции, поэтому вам нужно только один раз проверить эти внешние переменные, если они понадобятся. Совместным подпрограммам необходимо, чтобы эти проверки выполнялись после каждого yield() (так как его использование с исходной совместной программой было бы переведено в цепочку обратного вызова в реальном Javascript).

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

Что делает Async "лучше"?

Хуже лучше

На самом деле это своего рода идея "хуже - лучше". Вместо того, чтобы расширять язык Javascript, чтобы попытаться избавиться от его бородавок (и создать новые, на мой взгляд), Async - это чисто-Javascript-решение, чтобы покрыть их, например, makeup.

Явный поток управления

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

Если вы захотите сбросить первый уровень отступов вокруг аргументов async-методов, у вас нет дополнительных отступов против Co-Routines и только незначительное количество дополнительных строк объявлений function(callback) {, например:

var async = require('async');
var someArray = [1, 2, 3, 4, 5, 6, 7, 8, 9];
async.forEach(someArray,
function(number, callback) {
    //Do something with the number
    callback();
}, function(err) {
    //Done doing stuff, or one of the calls to the previous function returned an error I need to deal with
});

В этом случае вы знаете, что все переменные, используемые вашим кодом, могут быть изменены только до того, как ваш код будет запущен, если они не будут изменены вашим кодом, поэтому вы сможете легко отлаживать и есть только один "return": callback(). Вы либо выполняете обратный вызов без каких-либо успехов, либо передаете обратный вызов, когда что-то пошло не так.

Повторное использование кода не сложно

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

var async = require('async');

// Javascript doesn't care about declaration order within a scope,
// so order the declarations in a way that most readable to you

async.forEach(someArray, frazzleNumber, doneFrazzling);

var someArray = [1, 2, 3, 4, 5, 6, 7, 8, 9];

function frazzleNumber(number, callback) {
    // Do something to number
    callback();
}

function doneFrazzling(err) {
    // Do something or handle error
}

Функциональный, а не императивный

Асинхронный модуль не рекомендует использовать управление потоком в императивном стиле и поощряет (требует, чтобы части, пересекающие цикл событий) использовали функции для управления потоком.

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

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

В резюме

Волокно по самой природе расширения языка Javascript не может развить большую экосистему внутри Node.js, особенно когда Async получает 80% пути в отделе взглядов и не имеет ни одного из других недостатков co -программы в Javascript.

Ответ 2

Короткий ответ:

  • Async - это чистое/классическое решение для управления однопоточной асинхронностью
  • Fibers является расширением node.js для создания сопрограмм. Он включает фьючерсную библиотеку для управления однопоточной асинхронностью.
  • Существует множество других фьючерсных библиотек (перечисленных ниже), которые не требуют расширения javascript.
  • Q_oper8 - это модуль node.js для управления многопроцессорным concurrency

Обратите внимание, что ни один из них не предлагает "потоки", и поэтому никто не может говорить о многопоточности (хотя для этого также существует расширение node.js: threads_a_gogo).

Async vs Fiber/futures

Асинхронный

Async и Fibers/futures - это разные способы решения одной и той же проблемы: управление асинхронным разрешением зависимостей. Кажется, что у Async есть еще много "колоколов", чем многие другие библиотеки, которые пытаются решить эту проблему, что, на мой взгляд, делает ее хуже (гораздо больше когнитивных накладных расходов - то есть больше дерьма, чтобы учиться).

В javascript базовая асинхронизация выглядит следующим образом:

asyncCall(someParam, function(result) {
   useThe(result);
});

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

asyncCall1(someParam, function(result0) {
  asyncCall2(someParam, function(result1) {
   use(result0, result1);
  }
});

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

async.parallel([
  function(callback) {
    asyncCall1(someParam, function(result0) {
      callback(null,result0);
    },
  function(callback) {
    asyncCall1(someParam, function(result1) {
      callback(null,result1);
    },
  }
],
function(err, results) {
  use(results[0], results[1]);
});

Так что для меня это гораздо хуже, чем обратный ад, но для каждого из них я предполагаю. Несмотря на то, что он является уродливым, он позволяет одновременно выполнять вызовы (до тех пор, пока они делают неблокирующие вызовы ввода-вывода или что-то в этом роде). У Async есть еще много вариантов управления асинхронным кодом, поэтому, если вам интересно, посмотрите документацию.

Введите волокна/фьючерсы

В сопрограмме модуль Fibers включает фьючерсную библиотеку, которая использует сопрограммы для повторного ввода асинхронных событий в текущее продолжение (future.wait()).

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

Node.js имеет io-функции, такие как readFileSync, что позволяет вам ждать функции в строке, пока она получает файл для вас. Это не то, что обычно делается в javascript, и это не то, что может быть написано в чистом javascript - для этого требуется расширение типа Fibers.

Возвращаясь к тому же асинхронному примеру выше, это будет выглядеть с помощью волокон/фьючерсов:

var future0 = asyncCall1(someParam);
var future1 = asyncCall2(someParam);
use(future0.wait(), future1.wait());

Это значительно проще и так же эффективно, как и Async. Это позволяет избегать callback-hell элегантным эффективным способом. Однако есть (незначительные) недостатки. Дэвид Эллис превзошел многие из недостатков, поэтому я повторю только один действительный:

Несовместимость браузера

В силу того, что Fibers является расширением node.js, он не будет совместим с браузерами. Это сделает код обмена, который использует волокна невозможными как с сервером node.js, так и с браузером. Однако есть веские аргументы в пользу того, что большинство асинхронных кодов, которые вы хотите использовать на сервере (файловая система, база данных, сетевые вызовы), - это не тот код, который вы хотите использовать в браузере (ajax calls). Может быть, таймауты сталкиваются, но это похоже на это.

Кроме того, проект streamline.js имеет возможность преодолеть этот пробел. Похоже, у него есть процесс компиляции, который может преобразовать код streamline.js, используя синхронизацию и фьючерсы в чистый javascript, используя стиль обратного вызова, похожий на теперь неподдерживаемый описательный Javascript. Streamline.js может использовать несколько разных механизмов за кулисами, один из которых - node.js Fibers, другой - генераторы ECMAScript 6, а последний - перевод в javascript в стиле обратного вызова, о котором я уже упоминал.

Более сложная отладка

Этот выглядит как действительный, хотя и незначительный, gripe. Даже если вы планируете использовать волокна/фьючерсы и не используете сопрограммы для чего-либо еще, все равно могут возникать запутывающие переключатели контекста из-за неожиданных точек выхода (и входа).

Вводит предзадачу в javascript

Это, вероятно, самая большая проблема с волокнами, поскольку у нее есть возможность (хотя и маловероятная) введения труднодоступных ошибок. В принципе, поскольку Fiber yield может привести к временному выходу набора кода к другой неопределенной функции, возможно, что некоторое недопустимое состояние может быть прочитано или введено. Подробнее см. в этой статье. Лично я считаю, что невероятная чистота волокон/фьючерсов и подобных структур хорошо стоит редких коварных ошибок. Еще много ошибок вызвано ужасным кодом concurrency.

Недопустимые захваты

  • Не в окнах: это больше не так.
  • Непознавание с сопрограммами: A. Непознание никогда не является причиной, чтобы что-то избегать. Если это хорошо, хорошо, независимо от того, насколько вы знакомы с ним. B. Хотя сопрограммы и урожаи могут быть незнакомы, фьючерсы - это легкая концепция для понимания.

Другие библиотеки фьючерсов

Существует множество библиотек, реализующих фьючерсы, где понятие можно назвать "фьючерсами", "отложенными объектами" или "promises". Это включает библиотеки, такие как async-future, streamline.js, Q, when.js, promiscuous, jQuery отложен, фьючерсы coolaj86, kriszyp promises и описательный Javascript.

Большинство из них используют обратные вызовы для решения фьючерсов, которые затрагивают многие проблемы. Однако они не так чисты, как волокна/фьючерсы, они намного чище, чем Async. Здесь тот же пример снова использует мой собственный async-future:

var future0 = asyncCall1(someParam);
var future1 = asyncCall2(someParam);
Future.all([future0, future1]).then(function(results) {
  use(results[0], results[1])
}).done()

Q_oper8

Q_oper8 действительно отличный зверь. Он запускает задания в очереди, используя пул процессов. Поскольку javascript является однопоточным *, а javascript не имеет встроенной потоковой передачи, процессы - это обычный способ использовать более одного процессора в node. JS. Q_oper8 предназначен как альтернатива управлению процессами с помощью модуля node.js child_process.

Ответ 3

Вы также должны проверить Step.

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

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

Ответ 4

Я использую jQuery Отложенные функции на клиенте и jQuery Отложенные для nodejs на сервере вместо вложенных обратных вызовов. Это значительно сократило код и сделало его настолько удобочитаемым.

http://techishard.wordpress.com/2012/05/23/promises-promises-a-concise-pattern-for-getting-and-showing-my-json-array-with-jquery-and-underscore/

http://techishard.wordpress.com/2012/05/29/making-mongoose-keep-its-promises-on-the-server/