Home > other >  firebase severtimestamp delay (w/ vanilla JS)
firebase severtimestamp delay (w/ vanilla JS)

Time:01-04

I am trying to create a live chat with vanilla JS and firebase. I'm able to add and get the "newest" message render to the DOM with the following codes:

add message

  async addChat(message) {
    const chat = {
      message,
      createdAt: serverTimestamp(),
    };

    return await addDoc(this.chat, chat);
  }

get message

  getChat(syncChat) {
    onSnapshot(this.chat, snapshot => {
      snapshot.docChanges().forEach(shot => {
        if (shot.type === "added") {
          syncChat(shot.doc.data());
        }
      });
    });
  }

render message to the DOM

  render(data) {
    const html = `
      <li >
      <span >${data.message}</span>
      <p >${formatDistanceToNow(data.createdAt.toDate(), {
        addSuffix: true,
      })}</p>
      </li>
    `;

    this.chatList.innerHTML  = html;
  }

Like I said, I can render the chat message no problem, but I realize the there's a time delay when message is added to firebase and timestamp is created. So when the first new message is displayed on the DOM, the time actually return null, and I have to refresh the page in order to display the actually time.

I am just wondering if there's anyway to fix that? I tried looking through the firebase doc and got nothing. I also did a little bit of digging on the interest but most of them are using a framework and not vanilla js.

Thanks for the help.

SOLUTION

  getChat(showChat) {
    const q = query(
      this.collection,
      where("room", "==", this.room),
      orderBy("createdAt", "asc")
    );
    this.unsub = onSnapshot(q, snapshot => {
      snapshot.docChanges().forEach(snap => {
        if (snap.type === "added") {
          showChat(snap.doc.data({ serverTimestamps: "estimate" }));
        }
      });
    });
  }

Thanks for the help! I have decide to use the snapshotoptions, the estimate servertimestamps, and everything works great.

CodePudding user response:

When you perform a write operation on a client, the Firestore SDK immediately invoked all local listeners with the new data - something typically referred to as latency compensation within Firebase.

So when you write a new document with a server-side timestamp, your onSnapshot listener gets called before the request is sent to the server, and at that point the value of the timestamp field will be null, since it hasn't been calculated yet.

Then when the server confirms that the write operation was completed, and what the timestamp value was, your onSnapshot listener gets called again, now with the correct value for the timestamp field. Since this is a change to the document you already got before, it is an event with type changed.

To display the update, your code needs to also handle events where the type is changed, and use that to update the DOM element that it added for the first event.

Alternatively you can ask the Firestore SDK to give you an estimated timestamp on the first event by passing an option to the data() call as shown here: Firebase Cloud Firestore how to set snapShotOptions

  •  Tags:  
  • Related