Closed jeffrson closed 1 year ago
This is not a bug. Your reading code async and expect it magically to be loaded from the server immediately.
const record = client.record.getRecord('recordName')
// You need to wait for the record to load from server first
record.whenReady(() => {
console.log(record.get())
})
Or in es6
const record = client.record.getRecord('recordName')
// You need to wait for the record to load from server first
await record.whenReady()
console.log(record.get())
Closing issue, if you have further questions around async code feel free to continue on this thread 👍
Actually it would be good to put log a warning for those who call .get before the record is in a when ready state.
If you could edit the title to ‘warn when accessing record before it has been asynchronously loaded from server’ that would be great thanks!
Well, I'm sorry. This wasn't clear to me from the docs: https://deepstreamhub.com/docs/client-js/datasync-record/
Your totally right, the docs are pretty bad in those regards. I’m looking into revamping everything at https://deepstream.io and will look into putting a much more detailed getting started guide or cookbook up!
If you have any other feedback please let me know! Just please don’t phrase them all immediately as bugs 😅
What about record.get() and record.set() returning a promise?
How does record.set() behave? Would it require .whenReady() as well to be sure, changes have been synchronized to all listeners?
It’s a bit more complicated 😅
Get doesn’t use a promise because it’s only async once, after that the overhead would be way too high. If you want to get the data without subscribing to changes you can use snapshot. That’s the same as get but uses a promise instead.
Set changes are buffered till the record is ready and then applied. This means the changes you make before ready are not on the actual record but are queues. This is really important as when using paths it merges the path into the data first.
If you want to stay on the safe side and not deal with any of the race conditions then just use the await whenReady afterwards. It’s not built into the getRecord since you might want to initialise thousands of records in parallel. Hope that makes sense!
Snapshot is stateless though which makes a difference in more complicated scenarios, but for starter guides I won’t go into that!
Okay, thanks! I'm not quite sure about the details, but I may keep asking :smirk:
Two question for now (it's still related IMO...):
Will .get without subscribe always return the same value? Should the "ready" event work here? Nothing happens...
let myRecord = client.record.getRecord( 'test/johndoe' );
myRecord.on('ready', () => console.log('Ready!'))
myRecord.set({
firstname: 'Jane',
lastname: 'Doe'
})
Subscribe with records is a purely client side event, getting the record is what creates the subscription to the server. Subscribe is a client side event listener that just notifies you of something changes.
So if you do
r = getRecord(name)
await r.whenReady()
r.get()
await BBPromise.delay(10) // pause for ten seconds
r.get()
The possibility of getting different results exists if a remote user updated it during that time
To get rid of the record and underlying subscription you need to do a
r.discard()
If however you do this:
r1 = getRecord(‘a’)
r2 = getRecord(‘a’)
r1.discard()
The subscription will remain open because another record is still active. You need to make sure you do a
r2.discard()
As well in order to remove the subscription entirely
You don’t listen to the ready event either, you have to use whenReady. That might actually be a bug tbh since we don’t propagate that event anymore. Reason why is in V3 we used a singleton pattern where getRecord returned the same instance each time but made memory leaks a total pain to work with. In V4 each record is a thin wrapper around the Singleton record which allows the discard to remove all subscriptions related to that record instead.
Great questions IMO, I should probably put that down as a breaking change.
Generally trying to move away from even listener in favour of actual functions since it has much better support and tbh event emitters are harder to document as well.
Apologies, will edit when I’m on computer, hard to write code via mobile
edit: still doesn't work, wierd lol
anyway - thank you so much for your explanations!
I small tip, wr wrap getRecord in a promise that resolves when ready and rejects when fail and have still not found any need for doing anything on a record before it's ready. It makes the code much easier to follow like:
const record = await getRecord(recordName); console.log(record.get());
I have a record "test/johndoe", which is not returned as I would expect. In fact it is empty (see setTimeout). Only when I uncomment the line marked with "<=" it works. So what might be wrong here? deepstream Server is running from vanilla docker image 4.0.0.