2017-08-10 90 views
7

在由谷歌的服務人員的例子之一,cache and return requests爲什麼獲取請求必須克隆到服務工作者?

self.addEventListener('fetch', function(event) { 
    event.respondWith(
    caches.match(event.request) 
     .then(function(response) { 
     // Cache hit - return response 
     if (response) { 
      return response; 
     } 

     // IMPORTANT: Clone the request. A request is a stream and 
     // can only be consumed once. Since we are consuming this 
     // once by cache and once by the browser for fetch, we need 
     // to clone the response. 
     var fetchRequest = event.request.clone(); 

     return fetch(fetchRequest).then(
      function(response) { 
      // Check if we received a valid response 
      if(!response || response.status !== 200 || response.type !== 'basic') { 
       return response; 
      } 

      // IMPORTANT: Clone the response. A response is a stream 
      // and because we want the browser to consume the response 
      // as well as the cache consuming the response, we need 
      // to clone it so we have two streams. 
      var responseToCache = response.clone(); 

      caches.open(CACHE_NAME) 
       .then(function(cache) { 
       cache.put(event.request, responseToCache); 
       }); 

      return response; 
      } 
     ); 
     }) 
    ); 
}); 

在另一方面,由MDN,Using Service Workers提供的示例中,並不克隆該請求。

this.addEventListener('fetch', function(event) { 
    event.respondWith(
    caches.match(event.request).then(function(resp) { 
     return resp || fetch(event.request).then(function(response) { 
     caches.open('v1').then(function(cache) { 
      cache.put(event.request, response.clone()); 
     }); 
     return response; 
     }); 
    }).catch(function() { 
     return caches.match('/sw-test/gallery/myLittleVader.jpg'); 
    }) 
); 
}); 

在谷歌例如高速緩存未命中的情況下

所以:

我明白我們爲什麼要克隆響應:因爲它是由cache.put消耗掉,我們仍然希望返回迴應請求它的網頁。

但爲什麼要克隆請求?在評論中說,它被緩存使用用於獲取的瀏覽器。這究竟意味着什麼?

  • 緩存中的哪個位置消耗了請求流? cache.put?如果是這樣,爲什麼不caches.match消費的要求?

回答

1

的評論對我來說似乎很清楚地說,爲什麼這些代碼的作者認爲克隆是必要的:

請求是一個流和只能使用一次消耗。由於我們通過緩存消耗了一次,並且一次通過瀏覽器消費,我們需要克隆響應。

請記住請求的body可以是ReadableStream。如果cache.match必須讀取流(或部分讀取流)以確定緩存條目是否匹配,則後續讀取fetch將繼續讀取,並且丟失cache.match讀取的任何數據。

如果它只在有限的情況下非常重要(除非Google示例中的代碼只是錯誤的而且沒有必要),並且因此在很多測試用例中失敗可能會起作用(例如,其中主體是null或字符串,而不是流)。請記住MDN非常好,但它社區編輯的,並且錯誤和糟糕的示例會週期性蠕變。 (這些年來我不得不修復幾個明顯的錯誤。)通常情況下,社區發現並修復它們。

+1

谷歌開發者網站基礎知識網站中的片段在實現方面有所不同。例如,Jake不會克隆請求[這裏](https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/#on-network-response) –

+0

@ Schrodinger'scat :heh,但在該代碼下面說:*「爲了提高內存使用率,您只能讀取一次響應/請求的主體。在上面的代碼中,.clone()用於創建可以單獨讀取的其他副本。「*(注意*」......回覆/請求的主體......「)*)。我真的無法從服務人員的規範中看出,在幾分鐘之內,我是否給予它,無論您是否需要。我的猜測是你做的,*如果請求的主體是流。我可能會測試它(當然,我真的只知道它是否失敗*)。 –

+0

嗯..而不是服務工作者規範,我猜這可能是記錄在緩存規範或獲取API規範..需要閱讀 –

0

fetch請求,不進行高速緩存,因此caches基本上不消耗request

因此,無需克隆。 - 然而,asked Jake on his write up earlier.

responsesputadded到高速緩存和/或可以流傳下來的then鏈JSON /文本/別的東西 - 這意味着,他們是/便可食用。

我的猜測是,如果你使用mutate東西,那麼,你需要克隆它。

一個read可能是做既不caches.match

我也假設,那可能是另一個原因是,在請求本身的讀取,是不是piped環比下滑,並通過caches.match作爲只讀一次,只讀只發生一次,但響應流,可能被傳送到其他變化/轉換/寫入管道

只是從流規範抓住..還沒解釋如何一切都加起來..也許我會離開給專家

所以,如果我想直到現在解釋我的理解,克隆什麼是理想的消耗,不要打擾否則。而在這種情況下,讀取本身並不會改變請求/將它寫入其他地方,因此不需要克隆

相關問題