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

feat(core,utils): abortable atom #1091

Merged
merged 27 commits into from
Aug 19, 2022
Merged

feat(core,utils): abortable atom #1091

merged 27 commits into from
Aug 19, 2022

Conversation

dai-shi
Copy link
Member

@dai-shi dai-shi commented Apr 11, 2022

ref: https://twitter.com/dai_shi/status/1513173028674617350

core doesn't depend on AbortController, only the one in utils does.

  • impl
  • tests
  • docs with codesandbox example

Sorry, something went wrong.

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
@vercel
Copy link

vercel bot commented Apr 11, 2022

This pull request is being automatically deployed with Vercel (learn more).
To see the status of your deployment, click below or on the icon next to each commit.

🔍 Inspect: https://vercel.com/pmndrs/jotai/ABcZfcxrpWuez2fMNMmCw9X9yLBw
✅ Preview: https://jotai-git-feat-abortable-atom-pmndrs.vercel.app

@codesandbox-ci
Copy link

codesandbox-ci bot commented Apr 11, 2022

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 5474804:

Sandbox Source
React Configuration
React Typescript Configuration
React Browserify Configuration
React Snowpack Configuration
Next.js Configuration
Next.js with custom Babel config Configuration
React with custom Babel config Configuration

@github-actions
Copy link

github-actions bot commented Apr 11, 2022

Size Change: +990 B (+1%)

Total Size: 146 kB

Filename Size Change
dist/esm/index.js 5.21 kB +81 B (+2%)
dist/esm/utils.js 5.04 kB +102 B (+2%)
dist/index.js 6.23 kB +91 B (+1%)
dist/system/index.development.js 5.44 kB +83 B (+2%)
dist/system/index.production.js 3.01 kB +52 B (+2%)
dist/system/utils.development.js 5.39 kB +113 B (+2%)
dist/system/utils.production.js 3.38 kB +77 B (+2%)
dist/umd/index.development.js 6.32 kB +87 B (+1%)
dist/umd/index.production.js 3.46 kB +37 B (+1%)
dist/umd/utils.development.js 9.74 kB +96 B (+1%)
dist/umd/utils.production.js 6.29 kB +76 B (+1%)
dist/utils.js 9.53 kB +95 B (+1%)
ℹ️ View Unchanged
Filename Size
dist/babel/plugin-debug-label.js 945 B
dist/babel/plugin-react-refresh.js 1.16 kB
dist/babel/preset.js 1.41 kB
dist/devtools.js 3.93 kB
dist/esm/babel/plugin-debug-label.js 801 B
dist/esm/babel/plugin-react-refresh.js 1 kB
dist/esm/babel/preset.js 1.25 kB
dist/esm/devtools.js 3.03 kB
dist/esm/immer.js 643 B
dist/esm/optics.js 668 B
dist/esm/query.js 1.17 kB
dist/esm/redux.js 254 B
dist/esm/urql.js 1.33 kB
dist/esm/valtio.js 540 B
dist/esm/xstate.js 872 B
dist/esm/zustand.js 289 B
dist/immer.js 726 B
dist/optics.js 938 B
dist/query.js 1.27 kB
dist/redux.js 314 B
dist/system/babel/plugin-debug-label.development.js 911 B
dist/system/babel/plugin-debug-label.production.js 677 B
dist/system/babel/plugin-react-refresh.development.js 1.1 kB
dist/system/babel/plugin-react-refresh.production.js 863 B
dist/system/babel/preset.development.js 1.36 kB
dist/system/babel/preset.production.js 1.05 kB
dist/system/devtools.development.js 3.22 kB
dist/system/devtools.production.js 2.29 kB
dist/system/immer.development.js 772 B
dist/system/immer.production.js 469 B
dist/system/optics.development.js 770 B
dist/system/optics.production.js 455 B
dist/system/query.development.js 1.32 kB
dist/system/query.production.js 1.08 kB
dist/system/redux.development.js 344 B
dist/system/redux.production.js 217 B
dist/system/urql.development.js 1.49 kB
dist/system/urql.production.js 1.01 kB
dist/system/valtio.development.js 652 B
dist/system/valtio.production.js 400 B
dist/system/xstate.development.js 981 B
dist/system/xstate.production.js 626 B
dist/system/zustand.development.js 377 B
dist/system/zustand.production.js 235 B
dist/umd/babel/plugin-debug-label.development.js 1.11 kB
dist/umd/babel/plugin-debug-label.production.js 839 B
dist/umd/babel/plugin-react-refresh.development.js 1.31 kB
dist/umd/babel/plugin-react-refresh.production.js 994 B
dist/umd/babel/preset.development.js 1.56 kB
dist/umd/babel/preset.production.js 1.19 kB
dist/umd/devtools.development.js 4.06 kB
dist/umd/devtools.production.js 2.75 kB
dist/umd/immer.development.js 871 B
dist/umd/immer.production.js 570 B
dist/umd/optics.development.js 1.08 kB
dist/umd/optics.production.js 671 B
dist/umd/query.development.js 1.42 kB
dist/umd/query.production.js 1.1 kB
dist/umd/redux.development.js 454 B
dist/umd/redux.production.js 322 B
dist/umd/urql.development.js 1.77 kB
dist/umd/urql.production.js 1.22 kB
dist/umd/valtio.development.js 722 B
dist/umd/valtio.production.js 500 B
dist/umd/xstate.development.js 1.45 kB
dist/umd/xstate.production.js 912 B
dist/umd/zustand.development.js 479 B
dist/umd/zustand.production.js 334 B
dist/urql.js 1.62 kB
dist/valtio.js 586 B
dist/xstate.js 1.31 kB
dist/zustand.js 344 B

compressed-size-action

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
Update,
Result extends void | Promise<void>
>(read: Read<Value>, write?: Write<Update, Result>) {
const { signal, abort } = new AbortController()
Copy link

@incepter incepter Apr 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not a jotai user, so may be my comment will be irrelevant 🙏

AbortController only works with fetch and axios and may be some other libraries.

Cancellations in general affect any asynchronous behavior: browser api (timeout, interval), Promises, async/await .. I suggest supporting a mechanism that allows cancellations of all kinds, and not instantiating an abort controller at each run.

In a library I am preparing, I solved this by allowing the user's function to register any amount of abort callbacks, that are invoked either by user action or by effect cleanup.

function myStateProducer(props) {
  props.onAbort(() => clearTimeout(id));
  props.onAbort(() => clearInterval(id));
  props.onAbort((reason) => controller.abort(reason));
}

This allows the user to easily implement cancellations of all kinds rather that relying on AbortController which isn't supported in legacy browsers.

How can we cancel atoms ? is there any abort function provided ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I understand, AbortController is a general subscriber, and has nothing to do with fetch and others. We can use it for anything. setTimeout/clearTimeout can work too. (DX-wise, not sure if it's ideal) It would be nice to have such usage in docs.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please take a loot at the two following links:

https://developer.mozilla.org/en-US/docs/Web/API/AbortController

https://caniuse.com/abortcontroller

The problem with this approach is that you rely on the abort controller to stop the execution, but in fact, the execution doesn't stop. The then and finally blocks will still be executed, and it s unpredictable if they contain a setter or a side effect.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My plan was to use signal.aborted. It's not super nice, though. Maybe there would be better solutions. What we keep in mind is we don't often directly use promises. In most cases we just use async functions.

I'm not sure if we are on the same page. Feel free to try your own idea. It can be AC based, or independent. We shouldn't need to change jotai core in either case.

(I feel like I'm missing some cases like complex dependency graph...

const { signal, abort } = new AbortController()
return atom((get) => {
const promise = read(get, { signal })
if (promise instanceof Promise) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For better support, I guess we should support thenable, not only promises.

ie:
typeof promise === 'function' and typeof promise.then === 'function'

Is this promise catched somewhere in case of rejection?

Copy link
Member Author

@dai-shi dai-shi Apr 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We heavily depend on instanceof Promise everywhere. So, that means general thenable is not supported by jotai in the first place.

Do you see an actual issue with not supporting thenable?

Is this promise catched somewhere in case of rejection?

What does this mean? It is cached in store.

@incepter
Copy link

incepter commented Apr 11, 2022

I may help with cancellations, but i ll need first to know how the repo and internals of jotai work.

If there is any document describing them somehwere ? thanks in advance.

@dai-shi
Copy link
Member Author

dai-shi commented Apr 11, 2022

I'm sure you already visited https://jotai.org. That covers mostly. Some comments in source code may help, but it will still require the understanding of public API first.

@dai-shi dai-shi linked an issue Apr 12, 2022 that may be closed by this pull request
@vercel
Copy link

vercel bot commented Apr 16, 2022

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated
jotai ✅ Ready (Inspect) Visit Preview Aug 14, 2022 at 2:56AM (UTC)

@dai-shi dai-shi marked this pull request as ready for review August 14, 2022 02:56
@dai-shi dai-shi merged commit 14c9aac into main Aug 19, 2022
@dai-shi dai-shi deleted the feat/abortable-atom branch August 19, 2022 00:07
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

Successfully merging this pull request may close these issues.

Discussion: How to cancel derived async atom?
2 participants