Fetch超時設定和終止請求
1.基本使用
Fetch 是一個新的端獲取資源的介面,用於替換笨重繁瑣XMLHttpRequest.它有了Request 和 Response 以及Headers物件的概念,與後端語言請求資源更接近。
-
一個簡單的GET請求
fetch('https://www.baidu.com') .then(resp=>resp.text()) // 轉換成文字物件 .then(resp=>console.log(resp)) // 輸出請求內容 .catch(error => console.error(error));
-
一個簡單的POST請求
fetch('https://www.easy-mock.com/mock/5ca59ba44ba86c23d507bd40/example/getUser',{method:"post"}) .then(resp=>resp.json()) //轉換成Json物件 .then(resp=>console.log(resp)) //輸出Json內容 .catch(error => console.error(error));
更多Fetch相關詳細,可檢視MDN文件 developer.mozilla.org/en-US/docs/…
2.超時設定
在使用XMLHttpRequest可以設定請求超時時間,可是轉用Fetch後,超時時間設定不見了,在網路不可靠的情況下,超時設定往往很有用
ES6以後Promise 出現解決地獄回撥等不優雅的程式碼風格。個人理解這個更像是一個生產者和消費者的關係,檢視 Promise文件,有以下兩個方法
- Promise.race([promise1,promise2]) 傳入多個Promise物件,等待最快物件完成
- Promise.all([promise1,promise2]) 傳入多個Promise 物件,等待所有物件完成
有了以上知識後,結合函式setTimeout就可以實現超時設定
//ahutor:herbert qq:464884492
let timeoutPromise = (timeout) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("我是 timeoutPromise,已經完成了");
}, timeout);
});
}
let requestPromise = (url) => {
return fetch(url);
};
Promise.race([timeoutPromise(1000), requestPromise("https://www.baidu.com")])
.then(resp => {
console.log(resp);
})
.catch(error => {
console.log(error);
});
3.取消請求
將上邊的程式碼拷貝的瀏覽器控制檯並將network設定為Slow3G。執行就會發現,雖然我們在控制檯看到了超時資訊,但切換到netwok頁籤中發現請求依然正常進行中,並返回了正確的內容。這並不是我想要的結果,我希望超時時間到了,請求也應該終止。
fetch請求成功後,預設返回一個Response物件,那麼我們如何在程式碼中構造一個這樣的物件呢?
timeoutResp=new Response("timeout", { status: 504, statusText: "timeout " })
successResp=new Response("ok", { status: 200, statusText: "ok " })
AbortController 用於手動終止一個或多個DOM請求,通過該物件的AbortSignal注入的Fetch的請求中。所以需要完美實現timeout功能加上這個就對了
//ahutor:herbert qq:464884492
let controller = new AbortController();
let signal = controller.signal;
let timeoutPromise = (timeout) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(new Response("timeout", { status: 504, statusText: "timeout " }));
controller.abort();
}, timeout);
});
}
let requestPromise = (url) => {
return fetch(url, {
signal: signal
});
};
Promise.race([timeoutPromise(1000), requestPromise("https://www.baidu.com")])
.then(resp => {
console.log(resp);
})
.catch(error => {
console.log(error);
});
4.總結
第一次在專案中使用fetch,在面向API程式設計的過程中,發現fetch沒有超時的設定。第一時間查看了MDN文件以及向搜尋引擎找尋實現功能的靈感(copy+c)。有些朋友在settimeout中通過 reject(new Error('網路超時'))實現。其實這樣只是讓前端感知當前請求超時了,並沒有真正終止本次請求。所以必須藉助AbortSignal訊號物件。此功能目前還處於試驗階段,使用需謹慎。
demo地址 https://github.com/464884492/blog/blob/master/demo/fetch/fetchdem