В
Zionomicon как-то вскользь прошла тема FiberRef - но, как я обнаружил далее, это очень важная деталь имплементации самого Effect которая не упоминается в документации, поэтому хочу поделиться тем что накопал.FiberRef — Ref который привязан к конкретному файберу, является его локальным состоянием.// FiberRef.ts
declare const make: <A>(
initial: A,
options?: {
readonly fork?: ((a: A) => A) | undefined
readonly join?: ((parent: A, child: A) => A) | undefined
}
) => Effect<FiberRef<A>, never, Scope>
При создании
FiberRef можно указать стратегии копирования и слияния при fork-join файбера.Значения по умолчанию имеют смысл, чтобы не нарушать
fork-join identity закон файберов —Результат
fork и немедленного join файбера, должен быть идентичен результату синхронной работы программы{
fork: identity,
join: (_parent, child) => child
}
Playground с демонстрацией
FiberRef в Zionomicon
В демо видно что после слияния дочерний
FiberRef переопределяет родительский.Для чего же может пригодиться
FiberRef? Его можно использовать как контекст — хранить уровень логирования, какие-то аннотации и дефолты
В файбере-обработчике http-запроса — это может быть какая-то контекстная информация об этом запросе, юзер, роль и тд.
Все дефолтные сервисы
Effect предоставляются через этот механизм Так что можно сказать что
FiberRed — это такой альтернативный неявный способ передать контекст, он не влияет на типовой канал RНазвание
FiberRef отражает основное применение, но механизм гибче и опирается на состояние текущего выполнения — у файбера определен реджистри FiberRefs в который и складываются все FiberRef при создании. При fork-join файберов это реджистри клонируется и мерджатся согласно стратегиям которые задаются при создании рефов. Но можно изменить FiberRefs и текущего файбера — так как это вещь региональная, то есть ее можно переопределить. Например семейство Effect.locally* переопределяет FiberRef в оборачиваемом эффекте. // Effect.ts
export const locally: <A>(
self: FiberRef<A>,
value: A
): <B, E, R>(use: Effect<B, E, R>) => Effect<B, E, R>
В этом логе видно что файбер один и тот же #0, а значение
FiberRef временно переопределяется: const program = Effect.gen(function*() {
const fiberRef = yield* FiberRef.make(42)
// переопределяем 42 -> 46
yield* Effect.locally(fiberRef, 46)(Effect.gen(function*() {
const valueLocally = yield* fiberRef
yield* Effect.log({ valueLocally })
// INFO (#0): { valueLocally: 46 }
}))
const valueAfterLocally = yield* fiberRef
yield* Effect.log({ valueAfterLocally })
// INFO (#0): { valueLocally: 42 }
})