官术网_书友最值得收藏!

Handling request timeouts

Long-running requests can be the result of connectivity issues. Service workers are an ideal solution for overcoming these problems. Let's look at how we can implement a solution with service workers to handle request timeouts.

Getting ready

To get started with service workers, you will need to have the service worker experiment feature turned on in your browser settings. If you have not done this yet, refer to the previous recipe: Setting up service workers. Service workers only run across HTTPS. To find out how to set up a development environment to support this feature, refer to the following recipes: Setting up GitHub pages for SSL, Setting up SSL for Windows, and Setting up SSL for Mac.

How to do it...

Follow these instructions to set up your file structure:

  1. First, we need to create an index.html file as follows:
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Request Timeouts</title>
    </head>
    <body>
      <p>Registration status: <strong id="status"></strong></p>
    
      <script>
        if ('serviceWorker' in navigator) {
          navigator.serviceWorker.register(
            'service-worker.js',
            { scope: './' }
          ).then(function(serviceWorker) {
            document.getElementById('status').innerHTML = 'successful';
    });
        } else {
          document.getElementById('status').innerHTML = 'unavailable';
        }
      </script>
      <script src="https://code.jquery.com/jquery-2.2.0.js"></script>
    </body>
    </html>
  2. Create a JavaScript file called service-worker.js in the same folder as the index.html file with the following code:
    function timeout(delay) {
        return new Promise(function(resolve, reject) {
            setTimeout(function() {
                resolve(new Response('', {
                    status: 408,
                    statusText: 'Request timed out.'
                }));
            }, delay);
        });
    }
    
    self.addEventListener('install', function(event) {
        self.skipWaiting();
    });
    
    self.addEventListener('activate', function(event) {
        if (self.clients && clients.claim) {
            clients.claim();
        }
    });
    
    self.addEventListener('fetch', function(event) {
      if (/\.js$/.test(event.request.url)) {
        event.respondWith(Promise.race([timeout(400), fetch(event.request.url)]));
      } else {
        event.respondWith(fetch(event.request));
      }
    });
  3. With your two files in place, navigate to index.html and open the DevTools. You will see the time out error logged on the console.

How it works...

In our index.html file, we're fetching a large uncompressed jQuery library:

<script src="https://code.jquery.com/jquery-2.2.0.js"></script>

In our service-worker.js file, the event listener of the install event is calling the skipWaiting() method, which forces the waiting service worker to become the active service worker:

self.addEventListener('install', function(event) {
    self.skipWaiting();
});

The skipWaiting() method is used inside the active event handler, which in turn uses Clients.claim() to ensure that updates to the underlying service worker take effect immediately, for both the current client and all other active clients:

self.addEventListener('activate', function(event) {
    if (self.clients && clients.claim) {
        clients.claim();
    }
});

In event listener for fetch, we pass in a Promise.race() function where the first iterable, which is timeout(400), gets resolved first:

self.addEventListener('fetch', function(event) {
  if (/\.js$/.test(event.request.url)) {
    event.respondWith(Promise.race([timeout(400), fetch(event.request.url)]));
  } else {
    event.respondWith(fetch(event.request));
  }
});

We will elaborate on the Promise.race() function soon. The timeout() function returns a promise with 408, which is the code for the request timed out status.

There's more...

The Promise.race() method returns a promise that resolves, or rejects, as soon as one of the promises in the iterable resolves or rejects, with the value or reason from that promise:

var p1 = new Promise(function(resolve, reject) { 
    setTimeout(resolve, 400, "one"); 
});
var p2 = new Promise(function(resolve, reject) { 
    setTimeout(reject, 100, "two");
});

Promise.race([p1, p2]).then(function(value) {
  // Not called              
}, function(reason) {
  console.log(reason); // "two"
  // p2 is faster, so it rejects
});

As you can see, two is faster, so the result is reject.

主站蜘蛛池模板: 武安市| 鹤岗市| 平阴县| 南乐县| 呼和浩特市| 维西| 嘉鱼县| 栾川县| 禄劝| 秦皇岛市| 醴陵市| 贵南县| 昌邑市| 宣恩县| 会理县| 肃宁县| 文成县| 清新县| 师宗县| 双牌县| 万州区| 黔西县| 扶绥县| 安福县| 广饶县| 茶陵县| 交城县| 和政县| 双柏县| 多伦县| 吴忠市| 岳池县| 贵溪市| 普陀区| 隆子县| 高安市| 新竹县| 泸西县| 当涂县| 邵阳市| 通州区|