3

Ajax cancel

If you are familiar with xhr , you will know that Ajax can actually cancel the front end automatically, using XMLHttpRequest.abort() . Of course, this is not the era of slash-and-burn cultivation. Except for interviews, there may be basically no handwriting xhr axios :

The first is the old-fashioned 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.')

And then there's the new (not really new) AbortController:

 const controller = new AbortController()

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

After cancelToken and signal are passed to axios, they will be called by some mechanism 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 uses the publish-subscribe model to notify axios to cancel the request. Although this part is implemented by axios, it originated from a tc39 proposal cancelable promises proposal , but this proposal was abandoned.

AbortController is an interface that can already be used in browsers. As the name suggests, this is a controller dedicated to aborting behavior. The example of mdn also uses an Ajax request, but it is a fetch that is very popular. It can be seen that the practice of axios and fetch is consistent:

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

Other uses of AbortController

Of course, AbortController not only has a function of suspending Ajax, but also can see two usage examples by viewing the dom specification document :

A more practical example is to cancel the event listener with AbortController:

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

By passing --- AddEventListener to signal and running abort() to cancel event monitoring , this method is especially useful for anonymous callback functions.

Another example is for aborting promises . This is a relatively simple and self-documenting method... But in fact, it is not necessary to AbortController to achieve this function, as long as you find a way to get the promise reject just fine. I think the point of this example is to learn to use signal's 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);
    });
  });
}

In short, signal is a simple sender, and the function is biased towards canceling an operation. If you don't want to implement a pubsub object yourself in some case, use this and you're done.

This is the end of the introduction of AbortController. I wonder if everyone has gradually forgotten the title... Finally, I want to discuss whether it is useful to cancel Ajax?

To cancel or not to cancel, that is the question

In fact, this Ajax cancellation is just the front-end talking to itself, the back-end doesn't know to abort, the past request still needs to be executed, if the back-end does not have special processing, the back-end is still running hard if you cancel the 10s request .

So does the "optimization" seen in some articles, the so-called "cancel the request, only keep the last one" really makes sense?

Discuss on a case-by-case basis, for requests to modify data such as POST, even if the return is slow every time, the server is already processing it. It is undoubtedly mentally retarded to cancel the previous POST and send it again.

For GET, and only for some extreme operations, it may have a little effect. For example, if a super long table is obtained, the result is not obtained, and then the user uses search to quickly return a small amount of data and render it, and wait until the super long table is actually returned. Overwriting the searched data, cancel is really effective in this case. There is also the cancellation of download and upload, but it is estimated that it will rarely be used.

Finally, there is a reasonable but in fact useless benefit: after cancel , a request location can be saved . After all, the number of simultaneous requests for a domain name in the browser is limited. In more cases, timeout, which is more common than cancel, is more practical. Hmm...unless there are five or six super slow requests lined up at the same time, the rotation is still relatively fast...

My personal suggestion is that, in the final analysis, this so-called "cancellation" is a special treatment for very special cases. It's good to know this. There is no need to cancel the entire operation in the interceptor.

refer to


ssshooter
3.7k 声望1.8k 粉丝

« 上一篇
Vue 优化速查