关于axios:axios的cancelToken取消机制原理

63次阅读

共计 2000 个字符,预计需要花费 5 分钟才能阅读完成。

最近封装 axios,应用到勾销机制,发现应用十分简便,那么 axios 是如何实现的呢?简略钻研了一下

应用形式

axios 如何勾销一个申请提供了两种应用模式:

  • 第一种 调用 CancelToken 的静态方法 source
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.post('/user/12345', {name: 'new name'}, {cancelToken: source.token})
source.cancel('Operation canceled by the user.');
  • 第二种 本人实例化
let cancel;
axios.get('/user/12345', {cancelToken: new CancelToken(function executor(c) {cancel = c;})
});
cancel();

OK,能够看到应用非常简单,两种应用形式情理是一样的,分两步:

  1. 获取 cancelToken 实例,注入申请的配置参数
  2. 须要勾销的时候,调用 提供的 cancel 办法

剖析

剖析之前,用了几分钟思考了一下,可能是利用了状态机来管制的,具体怎么实现的,没想好。间接扒拉代码。

CancelToken.js

间接找 CancelToken 类,代码非常简单,如下:

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

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

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

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

概括一下外围逻辑就是,在实例上挂载了一个 promise,而后把 promise 的实例 和 更改 promise 状态的 resovle 函数对外抛出。

还能够看到 提供的两种应用办法并没有本质区别。

在内部,把 promise 实例提供给 axios 的配置参数,而后更改 promsie 状态的 resolve 函数,也就是 cancel 函数能够随便应用。
ok,到了这里就十分清朗了,也就是一个 promsie 管制的极简 状态机。
咱们有理由揣测,axios 外部拿到 promise 实例,只须要挂载一个 then 回调,回调里调用 xmlHttpRequest 的 abort 办法即可。

那么持续追踪验证一下是不是这么实现的。

adapters/http.js

搜寻关键词,能够看到第 284 行,注册了回调勾销函数:

 if (config.cancelToken) {
  // Handle cancellation
  config.cancelToken.promise.then(function onCanceled(cancel) {if (req.aborted) return;

    req.abort();
    reject(cancel);
  });
}

顺带还看到了 timeout 的解决:

if (config.timeout) {req.setTimeout(config.timeout, function handleRequestTimeout() {req.abort();
    reject(createError('timeout of' + config.timeout + 'ms exceeded', config, 'ECONNABORTED', req));
  });
}

嗯,意料之中,timeout 的解决机制也是一样的。

思考

看完代码,豁然开朗,原来这么简略。然而咱们确不肯定能写出这么优雅的代码。
这个案例,是一个简略的状态机,利用 promise 的异步个性,把变更外部状态的控制权移交内部,说白了就是一个闭包的利用,咱们能够有条有理的讲什么是闭包,然而确不肯定能使用的很奇妙,这种思维形式十分值得学习。

正文完
 0