0

I have a login page in React-Native. It works fine if I have an Internet connection, but I now want to handle the case where Internet (or the server) is down. The way I want to do this is using timeouts: the app should try to connect, and if there is no success in five seconds, I want to print an error message.

I have done this using the following code, taken from here:

export function timeout(
  promise,
  message = 'Request timeout',
  timeout = DEFAULT_TIMEOUT,
) {
  return new Promise((resolve, reject) => {
    const timeoutId = setTimeout(() => {
      console.log('timeout called');
      reject(new Error(message));
    }, timeout);
    promise.then(
      response => {
        clearTimeout(timeoutId);
        resolve(response);
      },
      err => {
        console.log('timeout NOT called');
        clearTimeout(timeoutId);
        reject(err);
      },
    );
  });
}

From the login page, we call it like this:

response = await timeout(
   getAccessToken(this.state.username, this.state.password),
  'Unable to connect to the server.',
);

where getAccessToken is an async wrapper around fetch. It works fine on a first login attempt (with Internet down). It waits for five seconds (DEFAULT_TIMEOUT) and then prints the 'Unable to connect to the server' error message. The problem is that if I click on the login button a second time, the app doesn't wait for five seconds and prints a generic 'Network error'. We can see the problem in logkitty:

[12:08:44] I | ReactNativeJS ▶︎ timeout called                (first click)
[12:08:49] I | ReactNativeJS ▶︎ timeout NOT called            (second click)

I don't understand why on a second login attempt the timeout is not triggered and the timeout automatically fails. What is the problem and how can I fix it?

BobMorane
  • 3,870
  • 3
  • 20
  • 42

1 Answers1

0

Promise objects returned from fetch() are rejected when a network failure or a request has not been completed.

If a network error occurs or CORS is misconfigured on the server side, the import () appointment is rejected by TypeError, so the second attempt will recognize the TypeError and immediately drop into the reject state.

To time out again, you must run the fetch() function after you connect the Internet. Then you have to turn off the Internet again and run the fetch()

NOTE: Promise objects returned from fetch() do not reject the HTTP error status. Even if the HTTP Status Code returns 404 or 500.

hong developer
  • 13,291
  • 4
  • 38
  • 68
  • So this is an expected behavior (from a `fetch` standpoint)? I have found nothing on this while researching this issue, would you be so kind as to back your answer with a reference? Thank you! – BobMorane Nov 01 '19 at 17:31
  • Yes, this can be applied to all API calls. For example, when you call API for the first time, the response value may come later, but when you try again, the response value may be faster than before. – hong developer Nov 01 '19 at 17:42
  • What your saying is what I am observing. The problem is even in the [fetch standard](https://fetch.spec.whatwg.org/), there seems to be no mention on this... – BobMorane Nov 02 '19 at 13:28
  • This is not part fetch, it is promise, you must be. Creates an object named Promise when you first run it. Because the parameters in it are also executed for the first time, they correspond to variables that receive and execute data. However, on the second run, Promise already has data. And the parameters are the same. This is why timeout reject reject err as functions of the running first. – hong developer Nov 02 '19 at 16:19