しおしお

IntelliJ IDEAのことなんかを書いてます

VueRouterでroute変更時にaxiosで実行中のリクエストをすべてキャンセルする

やりたいこと

VueRouterでroute変更時に、前のページで投げられていたリクエストを一括でキャンセルしたい。 これが出来ると、遷移前のページで大量にリクエストが投げられていた場合、遷移後のページのcreatedで実行するリクエストがすぐに実行出来るようになる。

サンプルコード

リクエストをキャンするするためのトークンなどを作る

リクエストをキャンするするためには、axiosでリクエストを投げる時にキャンセルトークンを設定する必要があるので、それを生成するクラスを作ってあげる。 リクエストキャンセル時には、以降のリクエストでは新しいキャンセルトークンが使えるようにしています。*1

import axios, { CancelTokenSource } from 'axios'

class RequestCanceler {
  private source: CancelTokenSource = axios.CancelToken.source()

  cancel() {
    this.source.cancel()
    this.source = axios.CancelToken.source()
  }

  token() {
    return this.source.token
  }
}
const requestCanceler = new RequestCanceler()

export {
  requestCanceler
}

axiosでリクエストを投げる

axiosでリクエストを投げるときには、configcancelTokenを設定してあげます。 キャンセルが行われると例外が上がるので、axios.isCancelを使ってキャンセルによる失敗なのかそれ以外なのかを判定してあげる必要があります。

import { requestCanceler } from './api'
import axios from 'axios'

axios.get(`http://localhost:8080/test`, {cancelToken: requestCanceler.token()}).then(res => {
  console.log(res.data)
}).catch(reason => {
  if (axios.isCancel(reason)) {
    console.log('cancel!!!!')
  } else {
    console.log('cancelじゃないよ')        
  }
})

route変更時にリクエストを一括キャンセルする

VueRouterbeforeEachでキャンセル処理を呼び出してリクエストを一括キャンセルしてあげます。

router.beforeEach((to, from, next) => {
  console.log('beforeEach')
  requestCanceler.cancel()
  next()
})

動かしてみた結果

VueRouterbeforeEachのログが出力された後に大量のcancel!!!が出力されているので、 キャンセル処理が動いてエラー処理でキャンセル処理の分岐に入っていることがわかりますね。

f:id:sioiri:20200223065955p:plain:w300

参考情報

*1:新しいトークンに変えないと、タイミングの問題なのか直後に投げるリクエストがキャンセル対象になったりしてしまいます…