Caching Effects
On this page
This section outlines several functions provided by the library that help manage caching and memoization in your application:
Function Name | Description |
---|---|
cachedFunction | Returns a memoized version of a function with effects. Memoization ensures that results are stored and reused for the same inputs, reducing the need to recompute them. |
once | Returns an effect that executes only once, regardless of how many times it's called. |
cached | Returns an effect that computes a result lazily and caches it. Subsequent evaluations of this effect will return the cached result without re-executing the logic. |
cachedWithTTL | Returns an effect that caches its result for a specified duration, known as the timeToLive . When the cache expires after the duration, the effect will be recomputed upon next evaluation. |
cachedInvalidateWithTTL | Similar to cachedWithTTL , this function caches an effect's result for a specified duration. It also includes an additional effect for manually invalidating the cached value before it naturally expires. |
cachedFunction
Returns a memoized version of a function with effects. Memoization ensures that results are stored and reused for the same inputs, reducing the need to recompute them.
ts
import {Effect ,Random } from "effect"constprogram =Effect .gen (function* () {constrandomNumber = (n : number) =>Random .nextIntBetween (1,n )console .log ("non-memoized version:")console .log (yield*randomNumber (10))console .log (yield*randomNumber (10))console .log ("memoized version:")constmemoized = yield*Effect .cachedFunction (randomNumber )console .log (yield*memoized (10))console .log (yield*memoized (10))})Effect .runFork (program )/*Example Output:non-memoized version:28memoized version:55*/
ts
import {Effect ,Random } from "effect"constprogram =Effect .gen (function* () {constrandomNumber = (n : number) =>Random .nextIntBetween (1,n )console .log ("non-memoized version:")console .log (yield*randomNumber (10))console .log (yield*randomNumber (10))console .log ("memoized version:")constmemoized = yield*Effect .cachedFunction (randomNumber )console .log (yield*memoized (10))console .log (yield*memoized (10))})Effect .runFork (program )/*Example Output:non-memoized version:28memoized version:55*/
once
Returns an effect that executes only once, regardless of how many times it's called.
ts
import {Effect ,Console } from "effect"constprogram =Effect .gen (function* () {consttask1 =Console .log ("task1")yield*Effect .repeatN (task1 , 2)consttask2 = yield*Effect .once (Console .log ("task2"))yield*Effect .repeatN (task2 , 2)})Effect .runFork (program )/*Output:task1task1task1task2*/
ts
import {Effect ,Console } from "effect"constprogram =Effect .gen (function* () {consttask1 =Console .log ("task1")yield*Effect .repeatN (task1 , 2)consttask2 = yield*Effect .once (Console .log ("task2"))yield*Effect .repeatN (task2 , 2)})Effect .runFork (program )/*Output:task1task1task1task2*/
cached
Returns an effect that computes a result lazily and caches it. Subsequent evaluations of this effect will return the cached result without re-executing the logic.
ts
import {Effect ,Console } from "effect"leti = 1constexpensiveTask =Effect .promise <string>(() => {console .log ("expensive task...")return newPromise ((resolve ) => {setTimeout (() => {resolve (`result ${i ++}`)}, 100)})})constprogram =Effect .gen (function* () {console .log ("non-cached version:")yield*expensiveTask .pipe (Effect .andThen (Console .log ))yield*expensiveTask .pipe (Effect .andThen (Console .log ))console .log ("cached version:")constcached = yield*Effect .cached (expensiveTask )yield*cached .pipe (Effect .andThen (Console .log ))yield*cached .pipe (Effect .andThen (Console .log ))})Effect .runFork (program )/*Output:non-cached version:expensive task...result 1expensive task...result 2cached version:expensive task...result 3result 3*/
ts
import {Effect ,Console } from "effect"leti = 1constexpensiveTask =Effect .promise <string>(() => {console .log ("expensive task...")return newPromise ((resolve ) => {setTimeout (() => {resolve (`result ${i ++}`)}, 100)})})constprogram =Effect .gen (function* () {console .log ("non-cached version:")yield*expensiveTask .pipe (Effect .andThen (Console .log ))yield*expensiveTask .pipe (Effect .andThen (Console .log ))console .log ("cached version:")constcached = yield*Effect .cached (expensiveTask )yield*cached .pipe (Effect .andThen (Console .log ))yield*cached .pipe (Effect .andThen (Console .log ))})Effect .runFork (program )/*Output:non-cached version:expensive task...result 1expensive task...result 2cached version:expensive task...result 3result 3*/
cachedWithTTL
Returns an effect that caches its result for a specified duration, known as the timeToLive
. When the cache expires after the duration, the effect will be recomputed upon next evaluation.
ts
import {Effect ,Console } from "effect"leti = 1constexpensiveTask =Effect .promise <string>(() => {console .log ("expensive task...")return newPromise ((resolve ) => {setTimeout (() => {resolve (`result ${i ++}`)}, 100)})})constprogram =Effect .gen (function* () {constcached = yield*Effect .cachedWithTTL (expensiveTask , "150 millis")yield*cached .pipe (Effect .andThen (Console .log ))yield*cached .pipe (Effect .andThen (Console .log ))yield*Effect .sleep ("100 millis")yield*cached .pipe (Effect .andThen (Console .log ))})Effect .runFork (program )/*Output:expensive task...result 1result 1expensive task...result 2*/
ts
import {Effect ,Console } from "effect"leti = 1constexpensiveTask =Effect .promise <string>(() => {console .log ("expensive task...")return newPromise ((resolve ) => {setTimeout (() => {resolve (`result ${i ++}`)}, 100)})})constprogram =Effect .gen (function* () {constcached = yield*Effect .cachedWithTTL (expensiveTask , "150 millis")yield*cached .pipe (Effect .andThen (Console .log ))yield*cached .pipe (Effect .andThen (Console .log ))yield*Effect .sleep ("100 millis")yield*cached .pipe (Effect .andThen (Console .log ))})Effect .runFork (program )/*Output:expensive task...result 1result 1expensive task...result 2*/
cachedInvalidateWithTTL
Similar to cachedWithTTL
, this function caches an effect's result for a specified duration. It also includes an additional effect for manually invalidating the cached value before it naturally expires.
ts
import { Effect, Console } from "effect"let i = 1const expensiveTask = Effect.promise<string>(() => {console.log("expensive task...")return new Promise((resolve) => {setTimeout(() => {resolve(`result ${i++}`)}, 100)})})const program = Effect.gen(function* () {const [cached, invalidate] = yield* Effect.cachedInvalidateWithTTL(expensiveTask,"1 hour")yield* cached.pipe(Effect.andThen(Console.log))yield* cached.pipe(Effect.andThen(Console.log))yield* invalidateyield* cached.pipe(Effect.andThen(Console.log))})Effect.runFork(program)/*Output:expensive task...result 1result 1expensive task...result 2*/
ts
import { Effect, Console } from "effect"let i = 1const expensiveTask = Effect.promise<string>(() => {console.log("expensive task...")return new Promise((resolve) => {setTimeout(() => {resolve(`result ${i++}`)}, 100)})})const program = Effect.gen(function* () {const [cached, invalidate] = yield* Effect.cachedInvalidateWithTTL(expensiveTask,"1 hour")yield* cached.pipe(Effect.andThen(Console.log))yield* cached.pipe(Effect.andThen(Console.log))yield* invalidateyield* cached.pipe(Effect.andThen(Console.log))})Effect.runFork(program)/*Output:expensive task...result 1result 1expensive task...result 2*/