vue-router + ajax로 이전 요청이 완료되지 않은 경우 이전 요청 취소

안녕하세요, 카미켄이라고합니다
최근에는 Vue.js(vuex + vue-router)에서 SPA를 만들고 있습니다.

이번은 사이드바 등의 구현을 하고 있었습니다만, 예를 들어 링크를 클릭한 직후에 「아, 미안, 정말은 이쪽이었다(포치)」라고 하는 때와 같은, 이전의 리퀘스트가 끝나지 않았을 때 router에서 이전 요청의 ajax 취소에 대한 의외로 정보가 없었기 때문에 정리해 보겠습니다.
(덧붙여 이번 예에서 ajax에 사용하고 있는 라이브러리는 axios가 됩니다.)

우선은 router로부터 ajax의 처리가 불리는 근처에서



코드를 소개합니다.
실제로 실장한 것에서 내용을 골고루 깎은 것으로, 코코에 써 있는 코드에 대해서는 테스트를 하고 있지 않습니다만 대체로의 흐름은 잡을 것입니다.

components 주위



우선은 리퀘스트 처리를 부르고 있는 router로 지정되고 있는 것과 같은 component의 코드입니다.
이곳은 어쩌면 평범합니다. vue-router 문서를 참고로 한 것입니다.

component.vue
<script>
// Request はaxiosを扱っているjsファイルに置き換えて参考にしてください
import Request from 'your/request.js'
export default {  
    // ... いろいろと略 ...
    created() {                                                      
        this.fetchData()                                             
    },                                                               
    watch: {                                                         
        // ルートが変更されたらこのメソッドを再び呼び出し            
        '$route': 'fetchData'                                        
    },                                                               
    methods: {           
        fetchData() {
            // vuexでLoaderのフラグを管理してたりする場合のフラグ
            this.$store.dispatch('setIsLoading', true)
            Request.post(this.$route.params.id, (result, errorMessage) => {
                this.$store.dispatch('setIsLoading', false)
                // 成功/失敗時の処理とか
                // (失敗時はdataや$storeなどに値が入らないように注意)
                // ローダー画面などをリクエスト中に代わりに出す場合には、
                // ajaxキャンセル時はローダー画面を一応終了するようにしたほうが良いかも
            }
        }
    },    
    // ... いろいろと略 ...
}


요청 주위



다음은 요청 관련을 다루는 axios 주위의 구현입니다.
취소할 때 토큰을 관리하거나 취소를 위한 메소드도 준비합니다.

request.js
import axios from 'axios'

class Request {
    constructor() {
        this.CancelToken = axios.CancelToken
        this.sources = {}
    }

    // ポストする部分のメインの処理
    post(id, callbackFn) {
        // POSTパラメータを作る
        let params = new URLSearchParams()
        params.append('id', id);

        // キャンセル用のトークンを作る(ついでに用途に応じてtokenが別々に保存されるようにする)
        let sourceKey = 'content1' // 実際の実装は用途に応じて動的に変えている
        this.sources[sourceKey] = this.CancelToken.source()
        let cancelToken = {
            cancelToken: this.sources[sourceKey].token
        }

        axios.post('url/to/api', params, cancelToken).then(response => {
            // ... いろいろと略 (エラーハンドリングとか) ...
            callbackFn(response, err)
        }).catch(thrown => {
            // キャンセルしたときは何もしたくないときの例
            // コールバック先でキャンセルによる終了が分かればOKです(実装はお任せします)
            let err = (axios.isCancel(thrown)) ? null : thrown
            callbackFn(null, err)
        })    
    }

    // キャンセルしたいときに叩く
    cancel(sourceKey) {
        if (typeof this.sources[sourceKey] != 'undefined') {
            this.sources[sourceKey].cancel('Operation canceled by the user.');
        }
    }
}

// シングルトンで生成
export default new Request()

(실제의 구현은 좀더 메소드 나누었습니다만, 여기에서는 흐름이 쫓기 쉽도록 정리했습니다)

Vue 인스턴스



취소 발화 처리는 루트의 Vue 인스턴스를 생성하기 전에 작성합니다.

index.js
import Vue     from 'vue/dist/vue.js'
import Router  from 'vue-router'
import routes  from './routes.js'

// 上記のaxiosを扱うJSファイル
import Request from 'your/request.js'

// ... いろいろと略 ...

Vue.use(Router)
const router = new Router({routes})

// キャンセル処理用
router.beforeEach((to, from, next) => {
    // 前の通信が終わる前に次がリクエストされる場合は前をキャンセル
    Request.cancel('content1')
    next()
})

// ... いろいろと略 ...

new Vue({
    el: '#app',
    router,
    store,
    render: h => h(App)
})

결과




제대로 취소 할 수있었습니다
이제 이전 요청을 기다릴 필요가 없습니다.

빠진 곳 등



리퀘스트시에 v-if로 전환해 로더 같은 화면에 내는 것 같은 처리로 하고 있었습니다만,
캔슬 처리가 되어도 로더로부터 제대로 돌아가 컴퍼넌트가 렌더링 되지 않게 하면, 다음의 router 처리가 발화하지 않는 현상에 고민되기도 했으므로, 일단 주의해 주세요.

그리고는, 취소하고 싶지 않은 처리라고도 물론 있다고 생각하므로, cancel의 토큰의 관리등으로 나누어 실장하는 등으로 조심합시다.

참고



abort all Axios requests when change route use vue-router
h tps : // s t c ゔ ぇ rf ぉ w. 코 m / 쿠에 s 치온 s / 51439338 / 아보 rt - 아 아 오 오 레 쿠에 sts - 우 - 짱 게 - 우세 - 에 - 로 r

좋은 웹페이지 즐겨찾기