Skip to content

FR: Option for Firestore promises to resolve after cache write when network is offline #1497

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

Closed
jbrew138 opened this issue Jan 25, 2019 · 4 comments

Comments

@jbrew138
Copy link

jbrew138 commented Jan 25, 2019

Describe your environment

  • Operating System version: Windows 10 Pro 1709
  • Browser version: Chrome 71.0.3578.98
  • Firebase SDK version: 5.8.0
  • Firebase Product: Firestore

Describe the problem

I've just now only learned that promises returned by Firestore for get()/update() won't resolve until the data reaches the server, and it's supposed to be expected behavior.

Following the usual pattern for asynchronous functions and promises, I've heavily relied upon the promises returned from Firestore to make sure that the data was set before continuing and updating the UI for the user. Most of the documentation examples on adding data use the promise.then().catch() pattern.

The offline data documentation states that

To use offline persistence, you don't need to make any changes to the code that you use to access Cloud Firestore data.

While the documentation should also be updated to specify that promises won't resolve until data is written to the server, it won't resolve the issue I've run into.

The project I'm working on now emphasizes being able to use it offline for long periods. However, because I've been relying on promises, I'll have to make extensive rewrites to remove the use of them in order to make it work as the SDK stands now. Since get()/update() are asynchronous functions to begin with, it doesn't seem logical to ignore promises in order to make things work offline.

For consistency's sake, I'm requesting that a flag be added to the options passed to enablePersistence() that would let promises returned by get()/update() resolve once the cache has been set and the write has been queued instead of waiting for the write to happen. Something like resolveWritePromisesOffline: true perhaps.

@mohshraim
Copy link

Almost semilar #520 (comment)

@schmidt-sebastian
Copy link
Contributor

@jbrew138 Thanks for letting us know about your issue.

In Firestore, when a write operation returns, the writes are immediately visible to the user. In fact, we will fire local "latency compensated" Query snapshots that include the result of the write immediately and before we communicate with the backend.

The lifecycle of a write can be simplified as follows:

  • A user calls set()/update()/add().
  • We synchronously persist the operation in our local cache.
  • We return control back to the user by returning an unresolved Promise.
  • We asynchronously fire any snapshot listeners that are affected by the operation.
  • We send the operation to the backend.
  • When the backend responds, we resolve or reject the Promise we returned earlier.

This behavior is fundamental to our SDK, and with latency compensation, you do not need to wait for the Promises to resolve until you can start reading back your data. While I agree that we can always improve our documentation, it is unlikely that we will offer a mode that would allow you to tweak this setting.

@jbrew138
Copy link
Author

I suppose the best workaround would be to set up single-use snapshot listeners as needed.

There are many ways how that could be abstracted, but for a quick example:

function snapshotPromise(ref) {
  return new Promise((resolve, reject) => {
    var unsubscribe = ref.onSnapshot((doc) => {
      resolve(doc);
      unsubscribe();
    }, (error) => {
      reject(error);
    });
  });
}

var doc_ref = firestore.collection("foo").doc("bar");
doc_ref.update({some: "information"});
snapshotPromise(doc_ref).then((doc) => {
  // Continue after update is written to local cache
  // Or check doc.metadata.hasPendingWrites if necessary
});

@mikelehen
Copy link
Contributor

Yep! That would work. You could also just use ref.get({source: 'cache'}) so you don't have to do the unsubscribe thing. And actually, you could use any method whatsoever on the Firestore SDK, since we execute all operations in order. So e.g. doc_ref.firestore.enableNetwork().then(() => ...) would actually guarantee the update() call has been completed and written to cache.

@firebase firebase locked and limited conversation to collaborators Oct 14, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants