axios 源码分析-取消请求

使用取消请求

有的时候我们会进行一些耗时比较长的请求,如果中途我们不想再继续了,如何能够取消请求呢,先看看axios官方文档关于取消请求的用法

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

axios.get('/user/12345', {
  cancelToken: source.token
}).catch(function(thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
    // handle error
  }
});

axios.post('/user/12345', {
  name: 'new name'
}, {
  cancelToken: source.token
})

// cancel the request (the message parameter is optional)
source.cancel('Operation canceled by the user.');

通过axios.CancelToken.source()得到一个对象,这个对象有两个属性,一个是token,一个是cancel方法,通过config把token传给我们想要取消的请求,然后调用cancel方法,就能够取消我们的请求,并且在catch里面得到我们调用cancel时传入的消息。

CancelToken

我们在axios源码找到CancelToken类,位置在/lib/cancel/CancelToken.js

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

可以看出我们调用的axios.CancelToken.source()方法返回的对象里面是tokencanceltoken就是CancelToken的实例。

其中cancel就是从实例里面拿到的c方法。我们再来看一下CancelToken的内容。

function CancelToken(executor) {
  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.prototype.throwIfRequested = function throwIfRequested() {
  if (this.reason) {
    throw this.reason;
  }
};

CancelToken传入一个函数,通过这个函数把function cancel(message)返回给了CancelToken.source().cancel

CancelToken.source().tokenpromisereason两个属性,promise 一直处于 pending状态,reason属性是一个Cancel类的实例,Cancel类的构造函数如下:

// /lib/cancel/Cancel.js
function Cancel(message) {
    this.message = message;
}

Cancel.prototype.toString = function toString() {
    return 'Cancel' + (this.message ? ': ' + this.message : '');
};

Cancel.prototype.__CANCEL__ = true;

可以看出reason属性里只有一个message。也就是我们取消请求时传入的消息。那是如何把这个消息抛出的呢,在axios的拦截器里面的调用CancelToken.prototype.throwIfRequested来抛出消息。

// /lib/core/dispatchRequest.js
function throwIfCancellationRequested(config) {
    if (config.cancelToken) {
        config.cancelToken.throwIfRequested();
    }
}
// 拦截器
module.exports = function dispatchRequest(config) {
    // 判断是否已经取消请求
    throwIfCancellationRequested(config);
    
    /* ... */
};

// /lib/cancel/CancelToken
CancelToken.prototype.throwIfRequested = function throwIfRequested() {
    if (this.reason) {
        throw this.reason;
    }
}

检测config.cancelToken是否有reason属性,如果有,将reason抛出,axios进入rejected状态。

我们知道axios其实就是帮我们封装了js的XMLHttpRequest对象,我们可以看一下XMLHttpRequest的文档,在文档中我们知道取消请求的方法是abort()的,所以前面处理那么多只是为了调用这个请求的abort()方法。

// lib/adapters/xhr.js
if (config.cancelToken) {
    // Handle cancellation
    config.cancelToken.promise.then(function onCanceled(cancel) {
        if (!request) {
            return;
        }

        // 取消请求
        request.abort();
        
        // promise进入rejected
        reject(cancel);
        // Clean up request
        request = null;
    });
}

这段代码把onCanceled传给了cancelToken.promise属性,所以当我们调用cancelToken.promiseresolve函数时,就会调用这个方法,通过这个方法调用request.abort()取消请求和改变请求的状态,使catch中抛出错误。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值