ajax、fetch、axios如何中断请求?

先来说一说“中断请求”的实际场景,当页面有多个tab页签时,每次切换页签都会去请求数据,频繁的切换就会去请求很多次,比如A页签切换到B页签,A页签请求完全是不必要的,这时候可以在切换时中断请求。

AbortController实验室功能,已经在主流浏览器实现,IE浏览器可以不支持,需要导入polyfill。

AbortController接口表示一个控制器对象,允许你根据需要中止一个或多个 Web请求。官网参考:https://developer.mozilla.org...

1、axios

axios已经实现AbortController,具体实践如下:

// fontend
import React, { useEffect } from 'react';
import axios from 'axios';

const AbortController = () => {

  const CancelToken = axios.CancelToken;
  const source = CancelToken.source();

  useEffect(() => {
    axios.post('http://127.0.0.1:8088/getData', {name: 'zs', pwd: '123456'}, {cancelToken: source.token})
      .then(res => {
        console.log(res);
      })
  }, []);

  const abort = () => {
    source.cancel('cancle request!');
  }

  return (
    <>
      
this is a abortController page.
) } export default AbortController;
// backend
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser')

const app = express();

app.use(cors({
  origin: '*',
  allowedHeaders: ['content-type'],
}))

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true })); 

app.post('/getData', (req, res) => {
  const {name, pwd} = req.body;
  if (!name || !pwd) {
    return res.json({
      code: 200,
      data: {},
      errorMessage: '参数不能为空'
    })
  }
  setTimeout(() => {
    res.json({
      code: 200,
      data: {name, pwd},
      errorMessage: '参数不能为空'
    })
  }, 5000);
})

app.listen(8088, () => {
  console.log('server is listening 8088');
})

image

早期切换页签时可以将source.cancel()放在useEffect返回函数里面执行,当页签下组件销毁时就取消请求

来看看axios是如何实现请求中断的,大致原理是从外部操作中断内部promise流

function CancelToken(executor) {
  if (typeof executor !== 'function') {
    throw new TypeError('executor must be a function.');
  }

  var resolvePromise;
  this.promise = new Promise(function promiseExecutor(resolve) {
    resolvePromise = resolve;
  });

  var token = this;
  executor(function cancel(message) {
    if (token.reason) {
      // Cancellation has already been requested
      return;
    }

    token.reason = new Cancel(message);
    resolvePromise(token.reason);
  });
}

CancelToken.source = function source() {
  var cancel;
  var token = new CancelToken(function executor(c) {
    cancel = c;
  });
  return {
    token: token,
    cancel: cancel
  };
};

c指cancel函数,当执行source.cancel()时从外部去操作CancelToken的私有属性resolvePromise,也就是resolve函数。

2、fetch

fetch直接使用AbortController来中断请求,详细如下:
首先安装abort-controller库,该库实现了web abort-controller。

yarn add abort-controller -S
import React, { useEffect } from 'react';
import Controller from 'abort-controller';

const AbortController = () => {

  const abortController = new Controller();

  useEffect(() => {
    fetch('http://127.0.0.1:8088/getData', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        name: 'zs',
        pwd: '123456'
      }),
      signal: abortController.signal
    })
  }, []);

  const abort = () => {
    abortController.abort()
  }

  return (
    <>
    
this is a abortController page.
) } export default AbortController;

3、$.ajax

$.ajax内部已经实现了abort功能。

ajax(settings?: JQuery.AjaxSettings): JQuery.jqXHR;

interface jqXHR extends Promise3, never,
        Ajax.SuccessTextStatus, Ajax.ErrorTextStatus, never,
        jqXHR, string, never>,
        Pick,
        Partial> {
        responseJSON?: any;
        // 中断请求
        abort(statusText?: string): void;

        state(): 'pending' | 'resolved' | 'rejected';
        statusCode(map: Ajax.StatusCodeCallbacks): void;
    }

具体例子:

import React, { useEffect } from 'react';
import $ from 'jquery';

const AbortController = () => {

  var abortController: JQuery.jqXHR | null = null;

  useEffect(() => {
    abortController = $.ajax({
      url: 'http://127.0.0.1:8088/getData',
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      data: JSON.stringify({
        name: 'zs',
        pwd: '123456'
      }),
      success: function(res) {
        console.log(res)
      }
    })

  }, []);

  const abort = () => {
    abortController?.abort()
  }

  return (
    <>
    
this is a abortController page.
) } export default AbortController;

你可能感兴趣的