一、什麼是Fetch ?
Fetch的定義
Fetch本質上是一種標準,該標準定義了請求、響應和繫結的流程。 Fetch標準還定義了Fetch () JavaScript API,它在相當低的抽象級別上公開了大部分網路功能,我們今天講的主要是Fetch API。Fetch API 提供了一個獲取資源的介面(包括跨域)。它類似於 XMLHttpRequest ,但新的API提供了更強大和靈活的功能集。 Fetch 的核心在於對 HTTP 介面的抽象,包括 Request,Response,Headers,Body,以及用於初始化非同步請求的 global fetch。
二、如何使用Fetch
fetch() 方法的使用
Fetch API 提供了一種全域性fetch()方法,該方法位於 WorkerOrGlobalScope 這一個 mixin 中 方法用於發起獲取資源的請求。它返回一個 promise,這個 promise 會在請求響應後被 resolve,並傳回 Response 物件。
fetch(input?: Request | string, init?: RequestInit): Promise<Response>
fetch(url, options).then(function(response) {
// 處理 HTTP 響應
}, function(error) {
// 處理網路錯誤
})
複製程式碼
fetch() 引數
fetch方法可以接收兩個引數input和options。
-
input 引數可以是字串,包含要獲取資源的 URL。也可以是一個 Request 物件。
-
options 是一個可選引數。一個配置項物件,包括所有對請求的設定。可選的引數有:
method: 請求使用的方法,如 GET、POST。
headers: 請求的頭資訊,包含與請求關聯的Headers物件。
body: 請求的 body 資訊。注意 GET 或 HEAD 方法的請求不能包含 body 資訊
mode: 請求的模式,如 cors、 no-cors 或者 same-origin。
credentials: 請求的 credentials,如 omit、same-origin 或者 include。為了在當前域名內自動傳送 cookie , 必須提供這個選項。
常用的fetch請求
HTML
fetch('/index/fetchHtml')
.then((res) => {
return res.text()
}).then((result) => {
document.body.innerHTML += result
})
.catch((err) => {
})
複製程式碼
JSON
fetch('/api/user/CaiCai')
.then((res) => {
return res.json()
})
.then((json) => {
console.log(json)
})
.catch((err => {
}))
複製程式碼
POST Form
function postForm() {
const form = document.querySelector('form')
const name = encodeURI(document.getElementsByName('name')[0].value)
fetch(`/api/user/${name}`, {
method: 'POST',
body: new FormData(form)
})
}
複製程式碼
POST JSON
fetch('/api/user/CaiCai', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'CaiCai',
age: '26',
})
})
複製程式碼
fetch注意事項
1. 錯誤處理
fetch只有在網路錯誤的情況,返回的promise會被reject。成功的 fetch() 檢查不僅要包括 promise 被 resolve,還要包括 Response.ok 屬性為 true。HTTP 404 狀態並不被認為是網路錯誤,所以Promise的狀態為resolve。
2. credentials 設定
fetch可以通過credentials自己控制傳送請求時是否帶上cookie。credentials可設定為include、same-origin、omit。include為了讓瀏覽器傳送包含憑據的請求(即使是跨域源)。如果你只想在請求URL與呼叫指令碼位於同一起源處時傳送憑據,請新增credentials: 'same-origin'。要改為確保瀏覽器不在請求中包含憑據,請使用credentials: 'omit'。
credentials 預設是“same-origin”,但是以下版本的瀏覽器實現了一個更老版本的fetch規範,其中預設是“忽略”: Firefox 39-60 Chrome 42 - 67 Safari 10.1 11.1.2 如果您的目標是這些瀏覽器,建議始終對所有fetch請求顯式指定憑據:'同源',而不是依賴於預設
3. 中止
fetch 自身並沒有提供 中止請求的方法。但是部分瀏覽器有實現AbortController,可以通過AbortController中止fetch請求
const controller = new AbortController();
const signal = controller.signal;
setTimeout(() => controller.abort(), 5000);
fetch('/api/user/CaiCai', {
signal, // 在option中加入signal
method: 'POST',
// credentials:'include',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'CaiCai',
age: '26',
})
}).then((res) => {
return res.json()
}).then((result) => {
console.log(result)
}).catch((err) => {
console.log(err)
})
複製程式碼
4.相容性
以下Can I Use上顯示的,是fetch的相容性情況,目前已經支援大部分瀏覽器,不支援的瀏覽器可以使用fetch polyfill
三、為什麼要用Fetch、而不用XHR
1、fetch返回的是promise物件,比XMLHttpRequest的實現更簡潔,fetch 使用起來更簡潔 ,完成工作所需的實際程式碼量也更少
2、fetch 可自定義是否攜帶Cookie
3、fetch在ServiceWorker中使用,至於ServiceWorker能有什麼優勢,會在未來寫ServiceWorker的時候回寫到
四、為什麼放棄fetch
首先,謝謝各位同學的指出文章的中問題,標題確實欠妥,文不對題。這裡補充下fetch的一些問題:
1.fetch不支援jsonp,如果專案中使用到JSONP,需要單獨實現一個JSONP。
2.fetch自身並沒有提供abort的方法,需要AbortController去處理中止,實現起來會繁瑣一點。並且AbortController相容性不是很好,不過@周公來同學指出,我們可以使用“abortcontroller-polyfill”。
3.在我們平常使用中,fetch相對XHR差別不大,並且就像@jokerapi同學說的“實際業務上,api 請求都是用再次封裝好的函式來處理的。底層是 Fetch 還是 XHR 影響不大。”。所以如果沒有特別的需求,從XHR升級到fetch的意義不大。但是在ServiceWorker中fetch會大放異彩。目前淘寶首頁就使用fetch+ServiceWorker來實現離線快取。
參考連結: