Is writing to firebase cloud firestore asynchronous in javascript?
And if it is, what is a way to deal with it?
My program is supposed to update a value into the database, and then pull that value out soon after, to do something with it.
Most of the times, the correct value comes out, however, sometimes the previous value is outputted, but when the page is refreshed and the same value is read from the database again, the correct value gets outputted.
So, I am assuming the issue must be that writing to the database is asynchronous, just like reading a database is.
".then" didn't seem to work.
Here is a simplified version of my code:
function updateDB{
db.collection("rooms").doc("roomsDoc").update({
roomTime: timeInput //timeInput is a variable defined (not shown in code here)
}).then
{
readDB();
}
}
function readDB(){
db.collection("rooms").doc("roomsDoc").get().then(function(doc) {
console.log(doc.data().roomTime);
});
}
The console.log is what outputs the wrong value sometimes.
yes it is asynchronous.
a good way to handle the problem you are having is to async/await.
first, you need to make the function you are doing this in an async function
then do something like this
async function FunctionName(){
// do some initial stuff
await write to the database
// do some intermediate stuff
await read from the database
}
All JavaScript client/browser APIs that work with files and networks are asynchronous - that is the nature of JavaScript.
then() does, in fact, work on the promises returned by Firestore's APIs (and all promises, for that matter). There are lots of examples of this in the documentation.
Without seeing your code, we don't know what you might be doing wrong.
Yes, it is asynchronous.
You should check the official documentation regarding this topic, it was very useful to me when trying to fetch data from the database/API:
Firebase Cloud Firestore
First you have to initialize your document ref and fetch data with get() async function and wait for the response using either then() or async/await method.
Hope this helps!
I think you made a typo here:
.then
{
readDB();
}
in this way, you are not really waiting for the completion of the first operation. To get what you want you need to write:
.then(() => readDB())
Related
Straight to the point, I am running an http server in Node.js managing a hotel's check-in/out info where I write all the JSON data from memory to the same file using "fs.writeFile".
The data usually don't exceed 145kB max, however since I need to write them everytime that I get an update from my DataBase, I have data loss/bad JSON format when calls to fs.writeFile happen one after each other immediately.
Currently I have solved this problem using "fs.writeFileSync" however I would like to hear for a more sophisticated solution and not using the easy/bad solution of sync function.
Using fs.promises results in the same error since again I have to make multiple calls to fs.promises.
According to Node's documentation , calling fs.writefile or fs.promises multiple times is not safe and they suggest using a filestream, however this is not currently an option.
To summarize, I need to wait for fs.writeFile to end normally before attempting any repeated write action, and using the callback is not useful since I don't know a priori when a write action needs to be done.
Thank you very much in advance
I assume you mean you are overwriting or truncating the file while the last write request is still being written. If I were you, I would use the promises API and heed the warning from the documentation:
It is unsafe to use fsPromises.writeFile() multiple times on the same file without waiting for the promise to be settled.
You can await the result in a traditional loop, or very carefully use .then() to "synchronize" your callbacks, but if you're not doing anything else in your event loop except reading from your database and writing to this file, you might as well just use writeFileSync to keep things simple/safe. The asynchronous APIs (callback and Promises) are intended to allow your program to do other things in the meantime; if this is not necessary and the async APIs add troublesome complexity for your code, just use the synchronous APIs. That's true for any node API or library function, not just fs.writeFile.
There are also libraries that will perform atomic filesystem operations for you and abstract away the implementation details, but I think these are probably overkill for you unless you describe your use case in more detail. For example, why you're dumping a database to disk as JSON as fast/frequently as you can, rather than keeping things in memory or using event-based incremental updates (e.g. a real, local database with atomicity and consistency guarantees).
thank you for your response!
Since my app is mainly an http server,yes I do other things rather than simply input/output, although with not a great amount of requests. I will review again the promises solution but the first time I had no luck.
To explain more I have a:function updateRoom(data){ ...update things in memory... writetoDisk(); }
and the function writetoDisk(){
fsWriteFile(....)
}
Making the function writetoDisk an async function and implementing "await" inside it still does not solve the problem since the updateRoom function will call the writetoDisk without waiting for it to end.
The ".then" approach can not be implemented since my updateRoom is being called constantly and dynamically .
If you happen to know 1-2 thing about async-await you are more than welcome to explain me a bit more, thanks again nevertheless!
ive found out that its a best practice for nodeJS / ExpressJS as an API-Endpoint for a ReactJS Software to only use asynchornus functions for mysql-querys etc.
But i really dont get how this should work and why it decrease performance if i didnt use it.
Please imagine the following code:
API Endpoint "/user/get/1"
Fetches every datas from user with id one and responds with a json content. If i use async there is no possibility to respond with the information gathered by the query, because its not fulfilled when the function runs to its end.
If i wrap it in a Promise, and wait until its finished its the same like a synchronus function - isnt it?
Please describe for me whats the difference between waiting for a async function or use sync function directly.
Thanks for your help!
If i wrap it in a Promise, and wait until its finished its the same
like a synchronus function - isnt it?
No, it isn't. The difference between synchronous and async functions in JavaScript is precisely that async code is scheduled to run whenever it can instead of immediately, right now. In other words, if you use sync code, your entire Node application will stop everything to grab your data from the database and won't do anything else until it's done. If you use a Promise and async code, instead, while your response won't come until it's done, the rest of the Node app will still continue running while the async code is getting the data, allowing other connections and requests to be made in the meantime.
Using async here isn't about making the one response come faster; it's about allowing other requests to be handled while waiting for that one response.
If you know that the Promise has already been resolved why can't you just call get() on it and receive the value? As opposed to using then(..) with a callback function.
So instead of doing:
promise.then(function(value) {
// do something with value
});
I want to be able to do the much simpler:
var value = promise.get();
Java offers this for it's CompletableFuture and I see no reason why JavaScript couldn't offer the same.
Java's get method "Waits if necessary for this future to complete", i.e. it blocks the current thread. We absolutely never want to do that in JavaScript, which has only one "thread".
It would have been possible to integrate methods in the API to determine synchronously whether and with what results the promise completed, but it's a good thing they didn't. Having only one single method, then, to get results when they are available, makes things a lot easier, safer and more consistent. There's no benefit in writing your own if-pending-then-this-else-that logic, it only opens up possibilities for mistakes. Asynchrony is hard.
Of course it not, because the task will run asynchronously so you can't get result immediately.
But you can use a sync/await to write sequential asynchronous code.
I'm creating a testing application that has 1000s of questions hosted on firebase. To prevent downloading the questions multiple times, I've implemented a questions service where in the constructor I download the questions:
this.db.list("questions/", { preserveSnapshot: true}).subscribe(snapshots => {...}
This downloads the questions and pushes them to a questions array so that I don't have to re download until the next session. I also have a function to serve the questions:
getQuestion(){
return this.questions[0];
}
However, because of the asynchronous nature of firebase, often times the data is not yet downloaded before getQuestion() is called, so it returns undefined.
Is there a proper way to implement this data store type pattern in angular, and make sure the async call in the constructor finishes before getQuestion() gets called?
I've tried adding a variable ready, initializing it to false, and setting it to true when the async call returns. Then, getQuestions() is modified to look like:
getQuestion(){
while(!this.ready()){}
return this.questions[0];
}
However this just causes the app to hang.
It's almost never necessary to use preserveSnapshot. Not having to worry about snapshots is one of the main benefits of using AngularFire. Just write this.db.list(PATH).subscribe(list =>.
You're confusing "downloading" with "subscribing". It is hardly ever a good idea to subscribe inside a service, and store the data locally--you'll never be exactly sure when the subscribe handler has run, as you have found.
Instead, the service should provide an observable, which consumers--usually components-will consume. Those consumers can subscribe to the observable and do whatever they want, include storing the data statically, or, preferably, you can subscribe to the observable directly within a template using the async pipe.
The general rule is to subscribe as late as possible--ideally in the template. Write your code as a set of observables which you map and filter and compose.
Firebase caches results and in general you don't need to worry about caching yourself.
Call getQuestion() function after Data from FireBase was downloaded.
Use blow code:
this.db.list("questions/").subscribe(list => {...} //etc
I have a Typescript function which converts a list of elements into a Map: Map.
Along this process of conversion, I need to modify something in the Map before returning the Map.
To obtain the info, I have to request a server so I have a http.GET request/subscription to get the value.
I am using the value right after the GET, and the server has not yet answer, so I am returning the Map with the wrong value.
(It comes later but too late).
Then I use this map in which I don't have the correct value
I need a mechanism to synchronize my function with the result of my GET request, before processing the Map later in my code (after returning the function).
How can I do this, I have been told that the Observable may be the solution, but I don't know how to do it.
I could use some help ;-).
Best regards,
Charles.
How can I do this, I have been told that the Observable may be the solution, but I don't know how to do it.
For async things you need some form of continuation mechanism. The popular choices are:
Callbacks
Supported natively e.g. setTimeout uses it
// Some code
setTimeout(() => {
// Some more code that executes after 1 second
}, 1000)
Promises
Supported natively (now). Some docs on TypeScript and how they help https://basarat.gitbooks.io/typescript/docs/promise.html
Observables
If your frameworks http returns observables you would need to use them.
Summary
You cannot halt execution of entire JavaScript as JavaScript's JS context is single threaded. You need to work with continuations. Check the docs of the library (e.g. angular / axios) or native api (fetch / XHR) you are using.