本文只关注axios源码之取消请求这个知识点的实现,如想看完整源码解析,请移步若川大佬的axios源码解析, axios是基于promise封装的,看axios需先对promise有所了解

  1. 取消请求的使用

     const CancelToken = axios.CancelToken;
     const source = CancelToken.source();
     var options = {
           url: 'xxxx',
           data: {},
           method: 'post',
           cancelToken: source.token
     };
     axios(options).then(function (res) {})
     // 调用cancel取消请求
     source.cancel('请求取消了');

    如上:调用source.cancel便可取消请求
    疑问:为什么source.cancel可以取消请求?

  2. 源码关于取消请求的实现

    1. 先看 axios\lib\adapters\xhr.js 里面是什么时候取消请求的,源码如下:

      if (config.cancelToken) {
            // Handle cancellation
            config.cancelToken.promise.then(function onCanceled(cancel) {
              if (!request) {
                return;
              }
              // 取消请求
              request.abort();
              reject(cancel);
              // Clean up request
              request = null;
            });
          }

      可看出在config.cancelToken.promise.then里面取消的
      疑问:config.cancelToken.promise.then什么时候调的,为什么source.cancel可以触发then的执行?

      1. 取消请求实现
        看源码之前。先看一个小例子:

        let t = new Promise((resolve) => {
            resolve('执行')
           })
           t.then(res => {
             console.log(res)
           })

        这里只要执行t.then, '执行'就被打印了,如果我想想在任何需要的地方去执行resolve('执行'),只能同过setTimeout去执行t.then, 但是在axios源码里面config.cancelToken.promise.then的调用时间已经定死了,我们只能通过source.cancel去控制config.cancelToken.promise.then的执行

        改造上方代码:

         let t = new Promise((resolve) => {
            // 把resolve引用存起来,需要执行的时候再执行
            delayedResolve = resolve
          })
           t.then(res => {
             console.log(res)
           })
          setTimeout(() => {
            delayedResolve('需要执行的时候在执行')
          }, 3000)

        可以看到,我们可以灵活控制delayedResolve的调用时间来触发t.then的执行
        上axios取消请求的源码:

        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
          };
        };

        分析:
        cancel肯定是一个函数,CancelToken接收一个函数executor, executor再接收一个函数 cancel = function cancel(message),并将此函数复制给CancelToken.source.cancel,cancel 里面调用了CancelToken.promise的resolve。 由此可以通过任意时间调用source.cancel来触发CancelToken.promise的resolve


小蜗牛
90 声望6 粉丝