Search code examples
javascriptpromisefetch-api

Promise.race for fetch tasks stops when one fetch url gives net::ERR_CONNECTION_REFUSED error


I tried to use an alternative url when one is not available but the race of promises was that the error of connection of one fetch rejected the process of another fetch.

In the code you can see the reverse function that is commented. When it is uncommented the race is not rejected. Maybe it is a tip. How to improve the code to use the alternative urls? (Good url is with the port 11112)

<!DOCTYPE html>
<html lang="pl">
<head>
    <meta charset="UTF-8">
    <title>Home</title>
    <meta content="width=device-width, initial-scale=1" name="viewport">
    <link href="" rel="stylesheet" title="style">
    <script>
        (() => {
            let urls = [
                'http://localhost:11997/style.css',
                'http://localhost:11112/style.css'
            ]
            // urls = urls.reverse();
            console.log(urls);
            let i = 0, promises = [];
            while (urls.length) {
                const url=urls.shift();
                console.log(url);
                promises.push(fetch(url, {method: 'HEAD'}));
            }
            p = Promise.race(promises);
            console.log(p);
            p
                .then(response => {
                    console.log(response.url);
                    return response.url;
                })
                .then(res_data => {
                    document.querySelector('[title=style]').href = res_data;
                })
            p
                .catch(e => console.log('trzczy', e))
        })();
    </script>
</head>
<body>
content
</body>
</html>

Error

(2) ['http://localhost:11997/style.css', 'http://localhost:11112/style.css']
index.html:19 http://localhost:11997/style.css
index.html:19 http://localhost:11112/style.css
index.html:23 Promise {<pending>}
index.html:20 
        
        
       HEAD http://localhost:11997/style.css net::ERR_CONNECTION_REFUSED
(anonymous) @ index.html:20
(anonymous) @ index.html:34
index.html:33 trzczy TypeError: Failed to fetch
    at index.html:20:31
    at index.html:34:11
index.html:20 
        
        
       Uncaught (in promise) TypeError: Failed to fetch
    at index.html:20:31
    at index.html:34:11
(anonymous) @ index.html:20
(anonymous) @ index.html:34
Promise.then (async)
(anonymous) @ index.html:29
(anonymous) @ index.html:34

Solution

  • Promise.race rejects when one ingredient rejects while the other is not yet settled. Use Promise.any instead, because this fulfills when one ingredient is fulfilled, even if the other is already rejected. See also here.

    function twoRequests() {
      return [
        fetch("https://httpbin.org/delay/1"),
        fetch("https://does.not.exist")
      ];
    }
    
    function logPromise(p, title) {
      p.then(function(value) {
        console.log(title, "fulfilled with value", value);
      }, function(err) {
        console.error(title, "rejected with error", err.message);
      });
    }
    logPromise(Promise.race(twoRequests()), "race");
    logPromise(Promise.any(twoRequests()), "any");