ajax、fetch、axios如何中斷請求?

先來講一說「中斷請求」的實際場景,當頁面有多個tab頁籤時,每次切換頁籤都會去請求數據,頻繁的切換就會去請求不少次,好比A頁籤切換到B頁籤,A頁籤請求徹底是沒必要要的,這時候能夠在切換時中斷請求。react

AbortController實驗室功能,已經在主流瀏覽器實現,IE瀏覽器能夠不支持,須要導入polyfill。jquery

AbortController接口表示一個控制器對象,容許你根據須要停止一個或多個 Web請求。官網參考:https://developer.mozilla.org...ios

一、axios

axios已經實現AbortController,具體實踐以下:web

// 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 (
    <>
      <div>this is a abortController page.</div>
      <div><button onClick={abort}>取消請求</button></div>
    </>
  )
}

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返回函數裏面執行,當頁簽下組件銷燬時就取消請求ajax

來看看axios是如何實現請求中斷的,大體原理是從外部操做中斷內部promise流express

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函數。json

二、fetch

fetch直接使用AbortController來中斷請求,詳細以下:
首先安裝abort-controller庫,該庫實現了web abort-controller。axios

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 (
    <>
    <div>this is a abortController page.</div>
    <div><button onClick={abort}>取消請求</button></div>
    </>
  )
}

export default AbortController;

三、$.ajax

$.ajax內部已經實現了abort功能。promise

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

interface jqXHR<TResolve = any> extends Promise3<TResolve, jqXHR<TResolve>, never,
        Ajax.SuccessTextStatus, Ajax.ErrorTextStatus, never,
        jqXHR<TResolve>, string, never>,
        Pick<XMLHttpRequest, 'abort' | 'getAllResponseHeaders' | 'getResponseHeader' | 'overrideMimeType' | 'readyState' | 'responseText' |
            'setRequestHeader' | 'status' | 'statusText'>,
        Partial<Pick<XMLHttpRequest, 'responseXML'>> {
        responseJSON?: any;
        // 中斷請求
        abort(statusText?: string): void;

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

具體例子:瀏覽器

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

const AbortController = () => {

  var abortController: JQuery.jqXHR<any> | 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 (
    <>
    <div>this is a abortController page.</div>
    <div><button onClick={abort}>取消請求</button></div>
    </>
  )
}

export default AbortController;
相關文章
相關標籤/搜索