关于javascript:Ajax-怎么取消要不要取消

45次阅读

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

Ajax cancel

如果你相熟 xhr,会晓得 Ajax 其实能够前端被动勾销,应用的是 XMLHttpRequest.abort()。当然当初也不是刀耕火种的时代,除了面试,可能根本不会手写 xhr,在无人不知的 axios 中有两种勾销办法:

首先是老式 cancelToken:

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.')

而后是新玩意(其实也不新)AbortController:

const controller = new AbortController()

axios
  .get('/foo/bar', {signal: controller.signal,})
  .then(function (response) {//...})
// cancel the request
controller.abort()

cancelToken 和 signal 传到 axios 之后,都会以某种机制调用 XMLHttpRequest.abort()

onCanceled = (cancel) => {if (!request) {return}
  reject(!cancel || cancel.type ? new CanceledError(null, config, request) : cancel
  )
  request.abort()
  request = null
}

config.cancelToken && config.cancelToken.subscribe(onCanceled)
if (config.signal) {
  config.signal.aborted
    ? onCanceled()
    : config.signal.addEventListener('abort', onCanceled)
}

cancelToken 是利用公布订阅模式告诉 axios 勾销申请,尽管这部分是 axios 本人实现的,然而源自于一个 tc39 提案 cancelable promises proposal,不过这个提案被废除了。

而 AbortController 是曾经能够在浏览器应用的接口,顾名思义,这就是一个专门用于停止行为的控制器。mdn 的举例用的也是 Ajax 申请,不过是至潮至 in 的 fetch,从中可见 axios 跟 fetch 的实际是统一的:

function fetchVideo() {controller = new AbortController() // 新建一个 controller
  const signal = controller.signal
  fetch(url, { signal}) // 在 fetch 办法传入 signal
    .then(function (response) {console.log('Download complete', response)
    })
    .catch(function (e) {console.log('Download error:' + e.message)
    })
}

abortBtn.addEventListener('click', function () {if (controller) controller.abort() // 调用 controller.abort 勾销 fetch
  console.log('Download aborted')
})

AbortController 的其余用处

当然 AbortController 不只有停止 Ajax 一个性能,通过查看 dom 标准文档还能看到两个应用示例:

一个比拟实用的例子是用 AbortController 勾销事件监听:

dictionary AddEventListenerOptions : EventListenerOptions {
  boolean passive = false;
  boolean once = false;
  AbortSignal signal;
};

通过向 AddEventListener 传入 signal,运行 abort() 即可 勾销事件监听 ,这个办法对 匿名 回调函数尤其有用。

另一个例子是用于 停止 promise。这是一个比拟简洁且自文档的办法……不过其实实现这个性能也不是非要 AbortController 能力做到,只有想方法拿到 promise 的 reject 就好了。我感觉这个例子的重点偏差于学会应用 signal 的 onabort:

const controller = new AbortController();
const signal = controller.signal;

startSpinner();

doAmazingness({..., signal})
  .then(result => ...)
  .catch(err => {if (err.name == 'AbortError') return;
    showUserErrorMessage();})
  .then(() => stopSpinner());

// …

controller.abort();

function doAmazingness({signal}) {return new Promise((resolve, reject) => {signal.throwIfAborted();

    // Begin doing amazingness, and call resolve(result) when done.
    // But also, watch for signals:
    signal.addEventListener('abort', () => {
      // Stop doing amazingness, and:
      reject(signal.reason);
    });
  });
}

总之,signal 就是个繁难发信器,而且性能偏差于勾销某操作。如果在某种状况下不想本人实现一个 pubsub 对象的话,用这个就完事了。

AbortController 的介绍就到此为止吧,不晓得大家有没有逐步遗记题目……最初是想讨论一下,勾销 Ajax 到底有没有用?

勾销还是不勾销,这是个问题

事实上,这个 Ajax 勾销只是前端自说自话,后端并不知道要停止,发过来的申请还是要执行的,后端没有非凡解决的话 10s 的申请你勾销了后端也依然在吃力地跑。

那么在一些文章中看到的“优化”,所谓“勾销申请,只保留最初一个”是否真的有意义呢?

分状况探讨,对于 POST 等批改数据的申请,每次发送即便返回慢,服务器也曾经在解决了,勾销上一个 POST 再反复发一个无疑是弱智行为。

对于 GET,且仅针对某些极限操作,或者有一点成果,例如:获取一个超长 table,后果没拿到,而后用户就用搜寻疾速返回大量数据并且渲染了,等到超长 table 真正返回就会笼罩掉搜寻的数据,这个状况 cancel 是真的无效的。另外还有下载上传的勾销,不过预计也很少会用到。

最初再说一个有情理然而事实上也是没什么用的益处:cancel 之后能 省一个申请地位,毕竟浏览器一个域名的同时申请数量是有限度的,更多状况下,比 cancel 更常见的 timeout 更实用。嗯……除非同时排着五六个超慢申请,否则轮转还是比拟快的……

集体倡议是,说到底这个所谓“勾销”都是极非凡状况的非凡解决,晓得这回事就好了,没有必要没事就在拦截器里整个勾销操作。

参考

  • dom spec
  • GitHub axios
  • mdn AbortController

正文完
 0