Как правильно войти в Sanctuary / Fluture?

Фон

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

const logInfoAsync = logger => message =>
    new Promise( ( resolve, reject ) => {
        setTimeout( () => {
            //random fail reason.
            if( message.length > 10 ){ 
                reject( "We have angered the Gods. Message is too big!" );
                return;
            }
            logger(message);
            resolve();
        }, 2000 );
    })

Использование:

const myLog= logInfoAsync( console.log );
myLog("Hello world!") // Rejected: "We have angered the Gods. Message is too big!"
myLog("Hello") // Resolved: "Hello"

проблема

Все идет нормально. У нас есть стандартный логгер, который иногда работает, а иногда злит Богов.

Теперь давайте предположим, что у нас есть последовательная серия async расчеты:

const { Future } = require("Fluture");

const myLogF= Future.encaseP( logInfoAsync( console.log ) );

//request.get returns a Future and so does saveDB
request.get("http://mywebsite.com")
    .chain( response => myLogF(`res is: ${res}`) )
    .chain( saveDB )
    .chain( ( ) => myLogF("Saved!") )
    .fork(
        err => console.log(`Something failed badly!: ${err}`),
        ( ) => console.log("Data saved to Olympus with great success!")
    );

В этом примере, что произойдет, если лесоруб разозлит богов? Что ж, нам не удалось сохранить данные! Возможно, запрос прошел нормально, и, возможно, данные были действительны, но из-за сбоя регистратора мы облажались!

Исследование

Теперь возможное решение этого было бы использовать Fluture.bimap после каждого журнала.Это было бы ужасно.

Я не хочу, чтобы мои журналы были более инвазивными, чем они есть, и я совершенно определенно не хочу, чтобы засорять мой код в стиле Promise try/catchs.

К сожалению для меня, это единственное, о чем я могу подумать... Я думаю, что лучшим вариантом будет, например, резервный логгер, console.error который используется, если myLogF потерпеть неудачу, но я в идеале хотел бы, чтобы это было невидимым.

Приложение не должно знать, что оно регистрируется вообще!

Вопросы

Итак, учитывая этот фрагмент, у меня есть следующие вопросы:

  1. Как бы вы продолжали цепочку, если журнал не работает?
  2. Как бы вы сделали сбой журнала и восстановление невидимым для приложения (не засоряя его эквивалентом (try/catch)?
  3. Какой шаблон наиболее часто используется для журналов?

1 ответ

Решение

Я бы сделал tap функция специально для фьючерсов, например:

const always = x => y => x
const tapF = f => x => f(x).fold(always(x), always(x))

Эта реализация tapF надеется f вернуть будущее, и оно заставит его разрешить с исходным входным значением.

Затем его можно использовать для регистрации, например:

request.get("http://mywebsite.com")
.chain( tapF(res => myLogF(`res is: ${res}`)) )
.chain( saveDB )
.chain( tapF(() => myLogF("Saved!")) )

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

Я считаю, что должен ответить на ваши первые два вопроса. Последний; "Каков наиболее часто используемый шаблон для журналов?", Я не уверен в этом. Есть несколько моделей, и две, которые я могу придумать:

  • Вход в качестве побочного эффекта внутри монады, которая представляет побочный эффект. Это то, что мы сделали с tapF,
  • Сбор журналов в памяти с помощью Writer Monad и запись их на краю программы. У меня нет опыта с этим подходом.
Другие вопросы по тегам