title: What is the difference between XMLHttpRequest and Service Worker API to preload assets of my web application
body: <p>I have the code below to preload specific files into the cache and it works fine using <code>XMLHttpRequest</code>. </p>
  
  <p>The question is what is the difference between my approach and using the <strong>Service Worker API</strong> if I only want to use it on Chrome. </p>
  
  <p>What are the pros and cons of Service Worker API compare to using <code>XMLHttpRequest</code>?</p>
  
  <p>If they both save data to <strong>browser's cache</strong> why I should use Service Worker?</p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>preload();
  
  function preload(){
  
  (function (global, factory) {
   typeof exports === 'object' &amp;&amp; typeof module !== 'undefined' ? module.exports = factory() :
   typeof define === 'function' &amp;&amp; define.amd ? define(factory) :
   (global.Preload = factory());
  }(this, (function () { 'use strict';
  
   function preloadOne(url, done) {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.responseType = 'blob';
    xhr.onprogress = event =&gt; {
     if (!event.lengthComputable) return false
     let item = this.getItemByUrl(event.target.responseURL);
     item.completion = parseInt((event.loaded / event.total) * 100);
     item.downloaded = event.loaded;
     item.total = event.total;
     this.updateProgressBar(item);
    };
    xhr.onload = event =&gt; {
     let type = event.target.response.type;
     let blob = new Blob([event.target.response], { type: type });
     let url = URL.createObjectURL(blob);
     let responseURL = event.target.responseURL;
     let item = this.getItemByUrl(responseURL);
     item.blobUrl = url;
     item.fileName = responseURL.substring(responseURL.lastIndexOf('/') + 1);
     item.type = type;
     item.size = blob.size;
     done(item);
    };
    
    xhr.onerror = event =&gt; {
          console.log('Error has happend so we restart the preloading..');
          preload();
          };
          
    xhr.send();
   }
  
   function updateProgressBar(item) {
    var sumCompletion = 0;
    var maxCompletion = this.status.length * 100;
  
    for (var itemStatus of this.status) {
     if (itemStatus.completion) {
      sumCompletion += itemStatus.completion;
     }
    }
    var totalCompletion = parseInt((sumCompletion / maxCompletion) * 100);
  
    if (!isNaN(totalCompletion)) {
     this.onprogress({
      progress: totalCompletion,
      item: item
     });
    }
   }
  
   function getItemByUrl(rawUrl) {
       for (var item of this.status) {
           if (item.url == rawUrl) return item
       }
   }
  
   function fetch(list) { 
    return new Promise((resolve, reject) =&gt; {
     this.loaded = list.length;
     for (let item of list) {
      this.status.push({ url: item });
      this.preloadOne(item, item =&gt; {
       this.onfetched(item);
       this.loaded--;
       if (this.loaded == 0) {
        this.oncomplete(this.status);
        resolve(this.status);
       }
      });
     }
    })
   }
  
   function Preload() {
    return {
     status: [],
     loaded: false,
     onprogress: () =&gt; {},
     oncomplete: () =&gt; {},
     onfetched: () =&gt; {},
     fetch,
     updateProgressBar,
     preloadOne,
     getItemByUrl
    }
   }
  
   return Preload;
  
  })));
  
  
   const preload = Preload();
  
   preload.fetch([
       'https://round-arm-authority.000webhostapp.com/Ultimate%20Video%20Hack/videos/vid1.mp4'
  
   ]).then(items =&gt; {
     // use either a promise or 'oncomplete'
     console.log(items);
   });
  
   preload.oncomplete = items =&gt; {
     console.log(items);
   }
  
   preload.onprogress = event =&gt; {
     console.log(event.progress + '%');
   }
  
   preload.onfetched = item =&gt; {
     console.log(item);
   }
   
  };</code></pre>
  </div>
  </div>
  </p>