Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@async-library/core #2

Open
ghengeveld opened this issue Sep 2, 2019 · 3 comments
Open

@async-library/core #2

ghengeveld opened this issue Sep 2, 2019 · 3 comments

Comments

@ghengeveld
Copy link
Member

ghengeveld commented Sep 2, 2019

@async-library/core will contain all the core functionality that Async Library provides. It will generally not be used directly, but be a dependency of @async-library/react-async-hook for example. It should have feature parity with react-async and react-async-hook (outside of React specifics).

This description is updated as the discussion unfolds.

Features

  • Standardized API (both in and out)
  • Full state management for a single instance in local state
  • No global store (otherwise you might as well use Redux Saga)
  • Cancellation (with AbortController)
  • DevTools integration (e.g. allow replaying a promiseFn)

To discuss:

  • Should we use generators instead of promises?
  • Should we use an internal state machine?
  • Should we allow users to create their own async state machine?

Core API

States:

  • initial nothing happened yet (or reinitialize was invoked)
  • pending promise is loading or paused
  • fulfilled promise was fulfilled with data
  • rejected promise was rejected with error

Config options:

  • fn async function that will be invoked on run
  • runOnInit flag to enable running on init (mount) [do we really need this?]
  • initialValue initialize value to a predefined value or error [should this be separate values for data and error?]

Callback options:

  • onInit when first initialized (i.e. mount)
  • onData when promise has fulfilled with data
  • onError when promise has rejected with error
  • onAbort when promise has aborted
  • onDestroy when destroying the instance (i.e. unmount)

Actions:

  • run invoke fn
  • abort cancel a pending promise and invoke AbortController::abort
  • reinitialize abort and reset state to initial

Metadata:

  • runCount number of times run was invoked (automatically or manually)
  • startedAt when the last run was invoked
  • finishedAt when the last promise was fulfilled or rejected

This API deviates quite a bit from React Async. Notably:

  • promiseFn and deferFn are combined into fn
  • promise is dropped as an option. You can just pass () => promise instead.
@phryneas
Copy link
Member

phryneas commented Sep 8, 2019

Should we use generators instead of promises?

What exactly are you targeting here? Internal API? External API? Saga-like effect yields with return values? Just flow control?

Just out of my head:

  • I would oppose generators for an outside API - not many people know how to use generators well and it might intimidate many users.
  • Generators for flow control internally are great
  • Generators where values are injected into the running generator by calling next break type safety. TS3.6 gives a little more security, but things like this can still not be properly inferred:
function* correct() {
    const promise = Promise.resolve(3);
    const result: number = yield promise;
}

function* problematic() {
    const promise = Promise.resolve(3);
    const result: string = yield promise; // this is wrong and cannot be checked by TS
}

So I'm not a big fan for generators that yield/inject more than exactly one fixed type (as that is possible with TS).

As for the point that currently, promises might leak memory and lead to uncaught promise rejections, we could cicumvent that:

  • all promises, even if cancelled are always resolved
  • instead of rejecting a cancelled promise, the resolving values contains a status indicator.

So those promises (that would in the case of async-library/react-async#92 (comment) ) cause an uncaught error. Would just either resolve to { status: "resolved", value: "..." } or {status: "cancelled", reason: "..." }

@ghengeveld
Copy link
Member Author

Agreed, I have a preference for promises over generators as well. However, will it allow us to implement subscriptions?

I've updated the issue to add a draft of the core API. It's by no means complete.

@phryneas
Copy link
Member

phryneas commented Sep 8, 2019

Not really, but a generator would make for a weird subscription, too. You'd have too loop over the Iterable or call next() manually. I'd rather use a callback for that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants