1. 程式人生 > >轉淘寶前端的一篇文章作備份

轉淘寶前端的一篇文章作備份

google https resolv selector 們的 捕獲 興趣 func 進制數

當前端也擁有 server 的能力

技術分享圖片

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

Fetch API

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

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

以前我們使用 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://example.com/test.json‘, true);
request.send(null);

而使用 Fetch API,我們只需要:

fetch(‘http://example.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,只是在這個不成熟的環境下,它目前不需要邁這麽大的步子。

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, 閻王‘));
});

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

由於 ServiceWorker 是對 Promise 友好的,響應時也可以模擬服務器休眠狀態:

addEventListener("fetch", function(evt) {
evt.respondWith(new Promise(function(resolve, reject){
setTimeout(function(){
resolve(new Response(‘Hi, 閻王‘));
}, 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://example.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 提供的文檔中深入學習下。

拓展閱讀

  • http://www.html5rocks.com/zh/tutorials/file/xhr2/
  • https://www.web-tinker.com/article/20882.html
  • https://davidwalsh.name/fetch
  • https://developer.mozilla.org/en-US/docs/Web/API/Cache
  • https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API

轉淘寶前端的一篇文章作備份