美文网首页让前端飞
仅仅知道如何终止XHR请求,或许对你来说是不够的!

仅仅知道如何终止XHR请求,或许对你来说是不够的!

作者: 小雨小雨丶 | 来源:发表于2020-02-22 17:43 被阅读0次

    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的内容。

    image

    我们注意两个地方,一个代表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>
    

    再次运行,我们会得到如下结果:

    image image

    从图中我们可以很清楚的看到,请求在2s后被终止,请求状态变为canceled,然后aborted的状态由false转变为true。

    就是这样,我们对fetch也进行的取消操作,还算是豁然开朗吧。嘻嘻。

    兼容性

    虽然AbortController已经诞生很长时间了,但是目前mdn上的定义还是实验性技术,查看mdn我们可以发现,其实主流浏览器大部分都支持了,如果我们开发的平台很新还是可以使用的,相信不远的将来,肯定会大批量使用。前端的道路也会越来越顺畅!

    image

    最后如果这边文章能帮给你带来一点帮助,欢迎关注,点赞,制作不易,与君共勉!

    image

    相关文章

      网友评论

        本文标题:仅仅知道如何终止XHR请求,或许对你来说是不够的!

        本文链接:https://www.haomeiwen.com/subject/anzlqhtx.html