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

syncable #30

Open
gregroyal opened this issue Jun 29, 2023 · 6 comments
Open

syncable #30

gregroyal opened this issue Jun 29, 2023 · 6 comments

Comments

@gregroyal
Copy link

I'm not sure the syncable example is working or I'm doing something wrong

I created this to demonstrate

https://codesandbox.io/s/sweet-surf-f2wq7y?file=/index.js

import App from "./App.svelte";
import { asyncable, syncable } from "svelte-asyncable";
import { get } from "svelte/store";

const app = new App({
  target: document.body
});

export default app;

let todos = asyncable(() => ["my async value"]);

todos.subscribe((result) => {
  result.then((r) => {
    console.log("this", r);

    const todosSync = syncable(todos, ["bleh"]);
    console.log(get(todosSync));
  });
});

I would expect todosSync to display "my async value" not "bleh"

@PaulMaly
Copy link
Member

PaulMaly commented Jul 5, 2023

Hi! As I can see, your example works as expected. As may you know, promises resolving in next tick, synable is a simple derived store which automatically resolve the promise for you and set a value asynchronously. FIrst time such store always triggering with default value. You can read about it in svelte docs in this chapter:

The callback can set a value asynchronously by accepting a second argument, set, and an optional third argument, update, calling either or both of them when appropriate.
In this case, you can also pass a third argument to derived — the initial value of the derived store before set or update is first called. If no initial value is specified, the store's initial value will be undefined.

get helper creates single-time subscription for you and immediately unsubscribe from the store. So, you will always get initial value here.

Your code looks a little bit strange to me, because seems you don't need to use syncable store here at all. If you describe what you need to do, I'll try to help you with that.

@gregroyal
Copy link
Author

Yah sorry I was trying to oversimplify a bit for the sake of the ticket. I'm new to using this lib and maybe I mis-understood how it might work

My use case is to use this library as a cache for a successful network call to eliminate calling the same endpoint over and over again each time a UI needs the results. Also to provide "stateful" UI's so the users know if things are still loading or there was an error

So say I create an asyncable that does a network call and stores that promise. When I use asynchronous methods to get the values in my various UIs, this use case works great!

There are a few places where I want the synchronous result of the promise because at that point in time I know this promise ran and theres active subscribers to the asyncable store. I dont want to force an async nature all the way up my call stack. syncable seemed to fit that need. I noticed when calling synable, it returns a store and not the store value. Thats where the get came in to get the store value not the store itself to make the call synchronous.

Do you have a live example on how to use syncable properly? I tried to recreate what you have in the README and ran into the same result

Is the syncable intention to only return a store of the results or the results themselves?

@gregroyal
Copy link
Author

gregroyal commented Jul 6, 2023

Ok my co-worker and I looked into this a bit more. It looks like syncable is working as expected only after it also has a subscription or a previous get call. I would expect it to work without having to subscribe twice

Heres an updated example
https://codesandbox.io/s/jovial-cache-jfqwv8?file=/index.js

@PaulMaly
Copy link
Member

Is the syncable intention to only return a store of the results or the results themselves?

syncable is a regular svelte's derived store which is just automatically resolve the promise stored in asyncable store for you. It not magical at all and it's always a store because we need to have reactivity for such things.

Do you have a live example on how to use syncable properly?

Very basic example how to use it you can find here: https://svelte.dev/repl/068f31a5dc8b4a24998d28762bf2a790?version=4.0.5

Heres an updated example https://codesandbox.io/s/jovial-cache-jfqwv8?file=/index.js

This example work as expected as well. derived store which is set its value asynchronously will always be resolved with the initial value at first time, because it start to calculate actual value from asyncable ONLY when first subscriber occured. So, it SHOUD give you some initial value, before async operation will be completed. Please, learn more about svelte's stores.

@gregroyal
Copy link
Author

The primary issue I'm having is I'm using the result of the syncable outside of svelte and just in normal ts. When I use $ with the syncable, it works perfect (like in your example). I think thats because the $ auto-subscribes to the store behind the scenes. If I use get from svelte/store inside of ts (or js), I require 1 to trigger the very first subscription on the syncable. Then it works as expected. Its not a huge deal, but maybe an improvement might be to auto subscribe or something to "kick" that first initial value. I can work around the double subscribe on my end no problem.

Thanks for this library though, I think its awesome!

@PaulMaly
Copy link
Member

PaulMaly commented Jul 13, 2023

If I use get from svelte/store inside of ts (or js), I require 1 to trigger the very first subscription on the syncable.

get function from svelte/store is just a way to create one-time subscription. It's equal to:

let value = 
store.subscribe(($store) => value = $store)();

syncable store is a derived store with asynchronously setting value because it resolving the promise for you. It means that syncable is a reactive stream which can be presented by following pipe divided to 3 logical parts:

(1) first subscription occurred -> return initial value immediately -> (2) wait until resolving a promise -> return actual value -> (3) return any next updates if dependant store has changed

Using get method you unsubscribe from this stream right after (1) step and don't get an actual value at all.

As you can see, syncable store as a derivative of asynchronous store, can't be fully synchronous. Essentially it just skipped pending state of a promise and gives you some default value until actual value is coming. So if try to compare the states of both stores it may look like:

asyncable: pending state -....-> resolved state with the value
syncable: initial value -....-> actual value

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