僅僅知道如何終止XHR請求,或許對你來說是不夠的!


TLDR:

當我們需要的時候,我們可以通過AbortController接口來終止一個或者多個請求。

前言

到目前為止,我們有兩個常用的基本的手段去發送請求進而局部刷新頁面內容,其一是XMR(XMLHttpRequest),其二是fetch,我們一個個說

XHR

對於XHR,我們或許已經很熟悉了,當我們想要發送一個請求的時候,我們可以這樣做:

const xhr = new XMLHttpRequest();
const method = 'GET';
const url = 'https://xxx';

xhr.open(method, url, true);
xhr.onreadystatechange = () => {
  if (xhr.readyState === 4) {
    // do something
  }
}
xhr.send();

當我們由於某種原因(比如重復請求)想要終止它的時候,我們只需要調用abort即可。

xhr.abort();

很方便也很簡潔,但是對於fetch呢?

fetch

首先我們看下fetch的基本定義:

看到這里我們已經知道了答案,但是我們需要再去了解一下上文所說的AbortController.

AbortController

最初es6引入fetch的時候,其實就是沒有abort這樣的功能,不過廣大程序朋友們還會希望能有這個靈活的api,所以在2015年就有人提了這個issue,再次之后大家嘗試了注入promise式的取消或者是其他hack等等,經過這份折騰最終我們迎來了AbortController和AbortSignal。

AbortController目前很簡單,有一個制度的屬性AbortController.signal和一個用來中斷請求的.abort()

光說也沒啥意思,咱看代碼說話:

// 啟動一個node服務,其中包括一個api和一個html頁面

const Koa = require('koa');
const fs = require('fs');
const app = new Koa();

const sleep = () => {
    return new Promise(res => {
        setTimeout(function() {
            res();
        }, 3000);
    });
};

app.use(async ctx => {
    if (ctx.request.url === '/api') {
        await sleep();
        ctx.body = 'Hello World';
    } else {
        ctx.status = 200;
        ctx.respond = false;
        fs.createReadStream('./test.html').pipe(ctx.res);
    }
});

app.listen(3000);

下面是test.html的內容

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        fetch('/api')
        .then((res) => {
            console.log(res, '請求成功');
        });
    </script>
</body>
</html>

啟動服務后,我們看下network的內容。

我們注意兩個地方,一個代表fetch請求,一個代表請求的延時時間,也就是我們定義的三秒

取消fetch

這時候我們想中斷,就可以這樣做:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // 增加了如下幾行
        const controller = new AbortController();
        const signal = controller.signal;
        console.log(signal, 'signal的初始狀態');
        signal.addEventListener('abort', function (e) {
            console.log(signal, 'signal的中斷狀態');
        });
        
        setTimeout(function() {
            controller.abort();
        }, 2000);
        // 增加部分結束

        fetch('/api', {signal})
        .then((res) => {
            console.log(res, '請求成功');
        });
    </script>
</body>
</html>

再次運行,我們會得到如下結果:

從圖中我們可以很清楚的看到,請求在2s后被終止,請求狀態變為canceled,然后aborted的狀態由false轉變為true。

就是這樣,我們對fetch也進行的取消操作,還算是豁然開朗吧。嘻嘻。

兼容性

雖然AbortController已經誕生很長時間了,但是目前mdn上的定義還是實驗性技術,查看mdn我們可以發現,其實主流瀏覽器大部分都支持了,如果我們開發的平台很新還是可以使用的,相信不遠的將來,肯定會大批量使用。前端的道路也會越來越順暢!

最后如果這邊文章能幫給你帶來一點幫助,歡迎關注,點贊,制作不易,與君共勉!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM