Muhammad Ameen
Muhammad Ameen

Reputation: 165

Firebase V9 does not give error in catch when offline

I want to set state in catch even if user offline but firebase V9 setDoc does not give anything in catch when user offline

For Example: in Authentication, if the user offline firebase gives (network error) in catch but in firestore "add document" no message from catch.

Example Code:

try {
    await setDoc(doc(db, "cities", "new-city-2"), data) 
    console.log("Document Written Successfully");
} catch (err) {
    console.log(`error found! ${err}`); 
}

Upvotes: 2

Views: 1035

Answers (2)

wenzf
wenzf

Reputation: 475

works on web v9, see docs from v8.

import { onLog } from 'firebase/app';

onLog((e) => {
  const { level, message } = e;
    if (level === 'warn') {
      console.log('connection interruption after intial load was success:', message);
    }
    if (level === 'error') {
      console.log('no connection on inital load:', message);
    }
});

Upvotes: 0

samthecodingman
samthecodingman

Reputation: 26196

This is by design thanks to Firestore's Offline Behaviour (queued up to the right spot, but I do recommend watching in full).

The promise will resolve once the server has acknowledged the request. If the server is currently unavailable, that request is cached within the SDK and attempted as soon as a connection is restored. During this window, the Promise will be kept in its pending state because that's the state its actually in - pending. While the promise may not resolve, all your local realtime listeners and such will still fire off and your app will function as normal - just offline.

Dealing with this behaviour is an exercise for the developer. One way to approach this would be to use Promise.race() to implement your own offline-handling logic.

As a quick & dirty example, here's a setDocWithTimeout implementation:

const setDocWithTimeout = (ref, data, options) => {
  const timeoutMS = options && options.timeout || 10000;
  const setDocPromise = setDoc(ref, data);

  return Promise.race([
    setDocPromise.then(() => ({ timeout: false })),
    new Promise((resolve, reject) => setTimeout(resolve, timeoutMS, { timeout: true, promise: setDocPromise }));
  ]);
}

which you can apply using:

try {
  const result = await setDocWithTimeout(doc(db, "cities", "new-city-2"), data);
  if (result.timeout) {
    // offline? (could be poor connection too)
    console.log("Document added to Firestore queue");
    // dismiss any blocking UIs/loading bubbles
    // tell user will be written to server later
    await result.promise; // wait for write to complete as before
  }

  // online! (or back online)
  console.log("Document written successfully!");
} catch (err) {
  console.error(`error found! ${err}`);
}

Alternatively where an error is thrown:

const setDocWithTimeoutError = (ref, data, options) => {
  const timeoutMS = options && options.timeout || 10000;
  const setDocPromise = setDoc(ref, data);

  return Promise.race([
    setDocPromise,
    new Promise((_, reject) => setTimeout(reject, timeoutMS, new Error("timeout"));
  ]);
}

which you can apply using:

try {
  await setDocWithTimeoutError(doc(db, "cities", "new-city-2"), data);
  console.log("Document written successfully!");
} catch (err) {
  console.error(`error found! ${err}`);
}

Upvotes: 3

Related Questions