當前端也擁有 Server 的能力

今天看了很多文章,比較感興趣的是 Cache API。它是瀏覽器 Request/Response 的緩存管理工具,其使用風格和運用場景讓我瞬間聯想到了 ServiceWorker 和 Fetch API,相信不少同窗也屢次看到過這兩個東西,本文會對它們作一個簡潔的介紹,並談一談我對這些新玩具的見解。html

Fetch API

傳統的 XMLHttpRequest,出了兩個版本,在 XHR2.0 中引入了跨源請求、上傳進度事件和對二進制數據的支持等,這些 API 的加強讓 AJAX 能夠很方便地與 HTML5 API 相結合,例如 File System API、Web Audio API、WebGL 等,讓前端對音視頻的處理和富客戶端元素的處理更加有親和力。前端

做爲一個與後端交互的通道,XHR2.0 的接口封裝依然過於底層。看看 jQuery 對 AJAX 的封裝,再回頭看看咱們今天要介紹的 Fetch API,不得不驚歎,瀏覽器已經在應用層面思考着功能的拓展,依託着 Promise 產出了十分友好的新一套接口。json

之前咱們使用 XHR 去請求一個資源,會這麼作:後端

// Just getting XHR is a mess!
if (window.XMLHttpRequest) {
  request = new XMLHttpRequest();
} else if (window.ActiveXObject) {
  try {
    request = new ActiveXObject('Msxml2.XMLHTTP');
  } 
  catch (e) {
    try {
      request = new ActiveXObject('Microsoft.XMLHTTP');
    } 
    catch (e) {}
  }
}
request.onreadstatechange = function(){
  // handle data;
};
request.open('GET', 'http://barretlee.com/test.json', true);
request.send(null);

而使用 Fetch API,咱們只須要:瀏覽器

fetch('http://barretlee.com/test.json').then(function(response) { 
  // Convert to JSON
  return response.json();
}).then(function(val) {
  console.log(val); 
});

對於 Text/HTML 和 Blob 等格式的請求和轉化也是異常方便:緩存

// Text/HTML 請求
fetch('/next/page').then(function(response) {
    return response.text();
}).then(function(text) {
  console.log(text); 
});

// Blob 流
fetch('flowers.jpg').then(function(response) {
  return response.blob();
}).then(function(blob) {
  document.querySelector('img').src = URL.createObjectURL(blob);
});

Fetch API 讓咱們更加關注請求和響應之間的交互,而不是聚焦在如何請求和如何處理響應兩個問題上。服務器

固然,它也存在幾個相比 XHR 不足的地方,首先它不能 abort 請求,同時也不能獲取請求過程當中的 progress 狀態,固然也沒有 timeout 超時處理。Fetch API 是基於 Promise 的,而 Promise 的狀態只有 pending、resolve、reject,不會出現諸如 pending(80%) 的狀態提示;咱們也沒法對一個 Promise chains 作 abort 處理,這些都是可以理解而且接受的。工具

我也相信,Fetch API 有能力提供這些狀態信息和附加的 API,只是在這個不成熟的環境下,它目前不須要邁這麼大的步子。post

ServiceWorker

ServiceWorker,簡單而言就是一個放在前端的 HTTP 攔截器,好比咱們要請求一個不存在的 URI 如:/test/a.html,直接請求就會響應 404,而若是咱們預先在 ServiceWorker 中註冊了這個地址,而且指定響應內容,當再次請求時,你會看到結果是存在的,舉個例子:學習

<!-- demo.html -->
<script>
navigator.serviceWorker.register("worker.js", {
  scope: 」/test/a.html"
}).then(function(){
  fetch(‘/test/a.html’).then(function(response) {
    return response.text();
  }).then(function(text) {
    console.log(text); 
  });
});
</script>

在 demo.html 文件中,咱們看到,將 /test/a.html 的請求交給 worker.js 來處理,處理方式爲:

// workker.js
addEventListener("fetch", function(evt) {
  evt.respondWith(new Response(「Hi, Barret Lee」));
});

在 demo.html 的回調中使用 Fetch 獲取/test/a.html 這個並不存在的內容,被 ServiceWorker 捕獲,交給 worker.js 處理並響應 Hi, Barret Lee 的文本,整個設計思路十分清晰,很輕鬆地攔截了來自客戶端的請求,並做出了響應。

因爲 ServiceWorker 是對 Promise 友好的,響應時也能夠模擬服務器休眠狀態:

addEventListener("fetch", function(evt) {
  evt.respondWith(new Promise(function(resolve, reject){
    setTimeout(function(){
      resolve(new Response(「Hi, Barret Lee」));
    }, 1000);
  }));
});

因爲 Fetch API 提供了對 Header 頭的修改,咱們幾乎能夠利用 ServiceWorker 實現真實 HTTP Server 的基本功能。

ServiceWorker 必定程度上改變了 Web 協做的交互模式,傳統狀況下,咱們須要開啓一個 Web Server,或者讓其餘人提供 HTTP Server,先後端之間交互,溝通成本比較高。而 ServiceWorker 把 HTTP Server 搬到了客戶端,咱們能夠在瀏覽器上輕鬆 Hold 住兩端的操做。這也算是 Web 技術棧融合的表現吧。

當咱們的目光放在 HTTP 的交互上,ServiceWorker 會有無限的想象空間,好比對 History API 的延伸思考,跨頁面共享問題,前端請求合併和分拆問題,mock 數據問題,先後端的聯調問題,類 graphQL 問題,數據的緩存更新和複用問題等等。

Cache API

Cache API,簡而言之就是一個 Request/Response 的緩存對象組,它的生命週期跟 ServiceWorker 是緊密相連的,它沒有失效時間,不刪除就會一直保持原樣。

caches.open('test-cache').then(function(cache) {
  cache.add('/index.html');
});

一個簡單的操做,就將 /index.html 這個頁面緩存了下來,若是你使用的是最新版的 Chrome,能夠打開 DevTools > Resources > Cache Storage,多了一個 test-cache 的緩存表,表中多出一項,Request 爲 http://barretlee.com/index.html, Response 爲 OK。以下方式能夠查看緩存內容:

caches.open('test-cache').then(function(cache) { 
  cache.keys().then(function(cachedRequests) { 
    console.log(cachedRequests);
  });
});

當瀏覽器處於 idle(空閒) 狀態的時候,會將 Cache 資源預加載到本地。這也讓我想起了 link 標籤中有一個 prefetch 功能,也會有同窗想到 Manifest,不過這兩個東西都是不能友好控制的,而 Cache 給咱們帶來了這樣的便利。

小結

我一直至關看好 Fetch API 系列相關的新接口,它的特色也很清晰,首先是基於 Promise 的實現,這個實現解決了回調和狀態控制的問題,而後是提供了應用級別的接口訪問,如今能夠把一個 HTTP 請求做爲可控的對象隨意操做,不管是 Request 仍是 Response 都在咱們的掌握之中,同時也必定程度解決了跨頁面資源共享的問題(至於跨頁面通信,咱們有 postMessage 和 MessageChannel 等工具)。

目前瀏覽器對 Fetch API 和 ServiceWorker 的支持都是比較可觀的,雖然 W3C 上的文檔狀態仍是 Draft 模式,相信隨着咱們對業務需求的更加明確,對前端認知的的不斷深刻,這些東西將很快被定爲 RFC。

本文沒有對 API 的使用作深刻的說明,一方面是由於這些東西能在 Google 上找到,其次,我以爲有些 API 的設計上還不夠成熟,從此會有增刪,感興趣的同窗能夠去 W3C 提供的文檔中深刻學習下。

相關文章
相關標籤/搜索