effection icon indicating copy to clipboard operation
effection copied to clipboard

Document equivalent to shared `Promise`

Open SebastienGllmt opened this issue 11 months ago • 0 comments
trafficstars

In typescript, a very common pattern is to share a promise in multiple places. For example:

class Foo {
  data: Promise<number>;

  constructor() {
    this.data = (async () => 5)();
  }

  async getData() {
    return await this.data;
  }
}

const foo = new Foo();
console.log(await foo.getData());

However, this can't be done directly with Operation as they can only be computed once:

const func = function* () {
  console.log("compute");
  return 5;
}

const started = func();

console.log(await run(() => started)); // returns 5
console.log(await run(() => started)); // returns undefined

Solution

A solution to this is to use the same run (aka the same Task) multiple times instead of creating a new task every time

const func = function* () {
  console.log("compute");
  return 5;
}

const started = func();
const started2 = run(() => started) // save the `Task` to reuse it

console.log(await started2); // returns 5
console.log(await started2); // returns 5 again!

main(function* () {
  // and this can even be used as a generator!
  console.log(yield* started2); // still 5
  console.log(yield* started2); // still 5
});

That is to say, I think Task is the go-to when you want this kind of Promise-like behavior. The only caveat to this approach is that it doesn't work when you try to chain the result of the task as described in solution (3) in #944

Other options

I noticed that effect-ts handles this differently by having a fork and join command: https://effect.website/docs/additional-resources/effect-vs-promise/#faq

SebastienGllmt avatar Dec 21 '24 19:12 SebastienGllmt