Pull to refresh

Comments 9

Во-первых, не понятно что делать если [...] выбросят несколько ошибок
Ну тут, очевидно, два варианта. Либо ловить первую, либо собирать их в массив. Promise.all работает по первой стратегии: если один из входов фейлит, то фейлит и их композиция с этой ошибкой. Тут плюс в том, что не нужно дожидаться ответов от всех входов, можно продолжать после первого фейла. И с другой стороны, попробуйте придумать ситуацию, когда нам действительно нужно получить весь массив ошибок? Как правило, нам достаточно того, что ошибка совершилась, и нужно переходить к её обработке. А что там с остальным, так разберёмся, когда этот блок перестанет выдавать ошибку.

А если мы уже ушли далеко вниз а в каком-нибудь parEach выше по таймеру выскочила ошибка?
Я, наверно, не до конца понимаю идею этой библиотеки. Как мы можем «уйти вниз», если ещё не получены все результаты? Документация грит:
parEach waits for all actions to call this() before moving along to the next action in the chain.
Если она ждёт ответа ото всех входов, то она дождётся и любой ошибки.

Поэтому, я решил, что в каждом YAFF должна быть только одна конструкция для обработки ошибок и она должна быть в конце.
Так нельзя, это всё равно что предлагать в синхронном программировании сделать один блок try-catch на всю программу и обязать программистов размещать catch в main. Многоуровневые catch просто необходимы. Например, у нас есть асинхронная либа, которая кормит нас такими потоками (flow). У неё есть внутренние ошибки, например, вызванные отсутствием файлов. Но на выходе, она преобразует невнятные внутренние ошибки в понятные ошибки из своего API. Или ещё пример: либа скармливает нам типизированные ошибки, мы хотим отлавливать их по-отдельности, на разных уровнях. Для всего этого нужны многоуровневые catch.

Смысль финального catch, это отловить все ошибки, чтобы программа хотя бы не падала, но в действительности, может быть ещё много промежуточных catch под более конкретные ситуации.
Есть еще forEach и он не ждет ничего.
Со временем я пришел к тому, что в моем коде остался только один catch и после seq для обработки удачного результата. Это примерно как в эрланге let it crash — мы программируем только оптимистичный случай когда все работает как надо. Если что-то пошло не так — ловим ошибку в finally и возвращаем тому кто вызывал: другая функция поймает ошибку точно так что в свой finally и таким образом она всплывет к вызывающему.
Catch вызывает много проблем с пониманием того куда передается поток управления. Вы использовали оригинальную библиотеку (Seq)?
мы программируем только оптимистичный случай когда все работает как надо
Да, понял стратегию. Это достаточно просто и наглядно, и ещё я думаю более производительно в реализации.

Оригинальную библиотеку я не использовал, потому у меня и возник такой вопрос. Я много использую Promise, но от основной идеи далеко не уйдёшь, асинхронный поток он и есть поток. В вашем примере указан как раз perEach, как я понял из документации, он-таки дожидается результата. forEach — нет, но в документации не сказано, что forEach сам может быть эмитентом ошибки. Вероятно, forEach нужен для вызова сайд-эффектов, поэтому он не влияет на состояние потока. В других либах для этого есть функция tap или doto.
К слову, это библиотека не является заменой обещаниям. Я использую и то и другое. Свою библиотеку — когда нужно организовать такой вот асинхронный поток. Обещания — когда этот поток может вызываться из разных мест или результаты работы нужны в разных местах, ну и для кеширования(или лучше сказать мемоизации?). Они прекрасно друг друга дополняют.
Рекомендую обратить внимание на Highland. Он несовместим с node-seq, как ваша библиотека, но в целом очень интересен, например, умеет принимать всё, от массивов до функций, промисов и потоков ноды. Просто ознакомьтесь с некоторыми решениями, очень интересная либа.

А по поводу отлова ошибок я бы хотел развеять ваше предубеждение, что их поведение неочевидно. Как правило, по взгляду на код можно определить как срабатывают catch, есть простое правило:
1. catch отлавливает все ошибки, возникшие выше него.
2. Если отработавший catch не выбросил ошибку сам, то она считается отловленной и следующие обработчики ошибок не срабатывают.
3. Если же он породил новую ошибку, то она будет передана ниже.
Так это реализовано в Promise и это очень наглядно (и тут полная аналогия с синхронным try-catch, только без многих уровней вложенности). Я думаю в node-seq такой же механизм, поэтому задавал вам уточняющий вопрос.
А с catch в оригинальной библиотеке происходили чудеса. В каких то случаях, после того как туда ловилась одна ошибка из того же parEach, библиотека переходила к тому, что написано после catch. И у меня даже были какие то костыли для обхода этой ситуации. Просто в какой то момент надоело и решил сначала исправить, а потом и переписать. Вот, смотрите:
  this.Seq([1,2,3,4,5,6,7])
    .parEach(function (num) {
      if (num % 2 == 0)
        return setTimeout(function () {this('ha-ha!')}.bind(this), 100)
      this(null, num);
    })
    .catch(function () {
      log('orig catch:', arguments);
    })
    .seq(function () {
      log('regual seq', arguments);
      this();
    })
    .catch(function () {
      log('should not be called', arguments)
    });

Этот код (использует оригинальную библиотеку) даст такой результат:
orig catch: { '0': 'ha-ha!', '1': 1 }
regual seq { '0': 1, '1': 2, '2': 3, '3': 4, '4': 5, '5': 6, '6': 7 }
orig catch: { '0': 'ha-ha!', '1': 3 }
regual seq {}
orig catch: { '0': 'ha-ha!', '1': 5 }
regual seq {}

т.е. элемент после catch будет вызван несколько раз. Перый раз — как положено, с аргументами. А потом — непонтно как.
UFO just landed and posted this here
В общем то, получается примерно то же, что придумал substack и переписал я.
iojs, конечно, хорошо. Но существующие проекты и на 0,12 ноду перевести не всегда можно и насчет будущего iojs у меня пока сомнения; поживем — посмотрим как они будут развиваться и куда двигаться. (Ужасно не люблю когда вот так вот плодят сущности.)
UFO just landed and posted this here
Only those users with full accounts are able to leave comments. Log in, please.