如何取消接口?

918 阅读1分钟

1.取消某个接口的请求

// 第一步,定义source
window.CancelToken = this.axios.CancelToken;
window.requestSource = window.CancelToken.source();
// 第二步,定义接口的cancelToken
this.axios.post('...', formData, {
    cancelToken: window.requestSource.token
})
// 第三步,取消接口
window.requestSource.cancel('cancel upload'); // cancel upload 打印在控制台

2.取消某个指定请求

data () {
    return {
        requestList: []
    }
}

fn () {
    const CancelToken = this.axios.CancelToken;
    this.axios.post('...', formData, {
        cancelToken: new CancelToken(c => {
            this.requestList.push({
                id: 'x',
                cancel: c
            })
        })
    })
    
    for(let i = 0; i < this.requestList.length; i++) {
        if (this.requestList[i].id === 'x') {
            // 取消请求
            this.requestList[i].cancel();
        }
    }
}

3.使用abort

npm install abort-controller -S

import Controller from 'abort-controller';

fn () {
    let abortController = new Controller();
    
    fetch('...', {
        method: 'POST',
        signal: abortController.signal
    })
    
    // 取消请求
    abortController.abort()
}

4.cancelToken 的原理

源码:

'use strict';
// var Cancel = require('./Cancel');

function Cancel(message) {
    this.message = message;
}

/**
* CancelToken 用来执行取消接口操作
* 返回 this
*
* @class
* @param {Function} executor The executor function.
*/
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) {
            // 已经执行过就直接 return
            return;
        }
        token.reason = new Cancel(message);
        // 这个方法可以在外部控制 CancelToken 内部的 Promise 的返回值是成功还是失败
        resolvePromise(token.reason);
    });
}
/**
* 如果已经执行过,就 throw Cancel 的实例
*/
CancelToken.prototype.throwIfRequested = function throwIfRequested() {
    if (this.reason) {
        throw this.reason;
    }
};
/**
 * 返回一个对象,
 * token 是 new CancelToken 得到的实例,
 * cancel 是 一个方法,CancelToken 中 传入 executor 的方法,调用它就可以 cancel 当前 CancelToken 的实例
*/
CancelToken.source = function source() {
    var cancel;
    var token = new CancelToken(function executor(c) {
        // 将 CancelToken 中 exector 方法传入的 cancel 方法的控制权拿出来
        cancel = c;
    });
    return {
        token: token,
        cancel: cancel
    };
};

module.exports = CancelToken;

使用的时候,先调用 axios.CancelToken.source(),拿到一个对象,里面包含了 token 和 cancel 。
token 是 CancelToken 的一个实例,可以访问内部的 Promise,cancel 则可以决定这个 promise 是成功还是失败,这样做就可以在外部控制 CancelToken 内部 promise 的返回值了。
调用 cancel 后就会触发 axios 中 promise.then 方法,源码如下:

if (config.cancelToken) {
    // 执行 cancel() 会触发这里的回调
    config.cancelToken.promise.then(function onCanceled(cancel) {
        if (!request) {
            return;
        }
        // 取消 request
        request.abort();
        reject(cancel);
        // 清空 request
        request = null;
    });
}