1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        封裝 axios 取消重復請求

        共 5400字,需瀏覽 11分鐘

         ·

        2021-01-05 10:42

        編者按:本文作者舒麗琦,奇舞團前端開發(fā)工程師

        在我們web開發(fā)過程中,很多地方需要我們取消重復的請求。但是哪種場合需要我們取消呢?我們如何取消呢?帶著這些問題我們閱讀本文。

        閱讀完本文,你將了解以下內容:

        • 需要取消重復請求的場景

        • 我們如何取消重復請求

        • axios如何取消重復的請求

        • 封裝axios

        • 如何給開源的項目提供源碼

        • 如何在本地調試npm包

        提出問題

        最近做的項目中,用的用戶經常遇到這樣的問題:

        • 用戶頻繁切換篩選條件去請求數(shù)據,初次的篩選條件數(shù)據量大。用的時間比較多。后面的篩選條件的數(shù)據量小。導致后面請求的數(shù)據先返回。內容先顯示在頁面上。但是等一段時間,初次(或者前面)的請求數(shù)據返回了, 會覆蓋后面的請求的數(shù)據。這就導致了篩選條件和內容不一致的情況。

        • 用戶點擊了一次提交按鈕,接口沒有很快響應,導致頁面沒辦法做邏輯語句判斷的提示。用戶覺得可能沒提交上,便會快速又點了按鈕幾次。如果后端沒有去重的判斷,就會導致數(shù)據中有很多條重復的數(shù)據。

        這些問題給用戶的體驗是很不友好的。那么取消無用的請求是很有必要的。

        解決思路

        我們用的請求庫是axios。那么我們可以在請求的時候攔截請求判斷當前的請求是否重復,如果重復我們就取消當前的請求。大致的實現(xiàn)過程如下:

        我們把目前處于pending的請求存儲(假如我們放在一個數(shù)組)起來。每個請求發(fā)送之前我們都要判斷當前這個請求是否已經存在于這個數(shù)組。如果存在,說明請求重復了,我們就在數(shù)組中找到重復的請求并且取消。如果不存在,說明這個請求不是重復的,正常發(fā)送并且把這個請求api添加在數(shù)據中,等請求結束之后刪除數(shù)組中的這個api。

        我們這個解決思路有了,但是axios如何取消請求的呢?我們先來了解下

        axios 如何取消請求

        查看axios文檔發(fā)現(xiàn)axios提供了兩種取消請求的方法(http://www.axios-js.com/zh-cn/docs/#%E5%8F%96%E6%B6%88)

        • 第一種方法

          通過axios.CancelToken.source生成取消令牌token和取消方法cancel

          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?{

          ????// 處理錯誤

          ??}

          });


          axios.post('/user/12345',?{

          ??name:?'new name'

          },?{

          ??cancelToken:?source.token

          })


          // 取消請求 (消息參數(shù)是可選的)

          source.cancel('Operation canceled by the user.');


        • 第二種方式

          通過傳遞一個 executor 函數(shù)到 CancelToken 的構造函數(shù)來創(chuàng)建 cancel token

          const?CancelToken?=?axios.CancelToken;

          let?cancel;


          axios.get('/user/12345',?{

          ??cancelToken:?new?CancelToken(function?executor(c)?{

          ????// executor 函數(shù)接收一個 cancel 函數(shù)作為參數(shù)

          ????cancel?=?c;

          ??})

          });


          // 取消請求

          cancel();


        封裝axios

        解決取消請求的思路有了,取消請求的辦法也有了,那么剩下的就是封裝了

        由于同事之前已經封裝了axios——very-axios(https://github.com/verymuch/very-axios) (基于 axios 進行二次封裝,更簡單、更統(tǒng)一地使用 axios)。那么我們就這個基礎上提一個pr吧。那么從現(xiàn)在開始我們就一步一步的來實現(xiàn),這個過程包含了【如何給開源的項目貢獻代碼】【如何在本地調試npm】如果已經了解的同學可以直接略過。

        準備工作

        由于同事已經封裝了axios并且已經開源了。那么我貢獻代碼的方式主要有兩種:

        • 代碼倉庫的管理者給我們添加這個倉庫的寫入權限,如果這樣,我們就可以直接提push。

        • 如果我們沒有權限(大多數(shù)情況)。我們使用經典的fork & pull request 的方式來提交代碼。

        我們采用的第二種方式。我們去 very-axios(https://github.com/verymuch/very-axios) 把代碼fork到自己的倉庫(如果你還沒有自己的github,需要自己注冊下哦)。


        那么你回到自己的github倉庫下面就會看有一個一摸一樣的項目


        那么我們現(xiàn)在就可以git clone這個倉庫的代碼到本地,新建branch進行開發(fā),就比如我新建了一個這樣的branch:

        現(xiàn)在已經有本地的代碼了,但是我們如何本地化調試npm包呢?那就需要npm link

        首先在我們要修改的npm 包中npm link


        之后我們會得到

        /Users/shuliqi/.nvm/versions/node/v12.17.0/lib/node_modules/very-axios?->?/Users/shuliqi/study/axios/very-axios

        這意思就是我們把very-axios鏈接到全局的node_modules

        然后我們進入我們my-project-of-axios 目錄下面執(zhí)行npm link very-axios 如圖:

        這意思就是very-axios被安裝在my-project-of-axios 下面了。very-axios的修改都會同步到my-project-of-axios。就實現(xiàn)本地測試了。

        我們在my-project-of-axios中的HelloWorld.vue文件中做列子。

        如果這里看的不是很懂的同學可以看看這兩篇文章:如何在本地調試npm包(https://github.com/allenGKC/Blog/issues/13)。如何使用 GitHub Flow 給開源項目貢獻代碼(https://juejin.im/post/6844903636863041550)


        開始封裝

        準備工作完成了, 那我們開始封裝的事情。根據我們之前的思路。我們采用axios 如何取消請求的第一種方式。

        聲明一個Map。用來存儲每個請求的 標識 和 取消的函數(shù)

        // 存儲每個請求的標識和取消的函數(shù)

        this.pendingAjax?=?new?Map();

        自定一個字段來讓用戶自己決定是否需要取消重復的請求

        // 是否取消重復的請求

        cancelDuplicated?=?false,

        自定一個字段來讓用戶是否有全局的統(tǒng)一的設置重復標識的函數(shù)。如果沒有設置全局的統(tǒng)一的函數(shù),則默認是請求的methodurl作為重復的標識

        // 生成重復標識的方式

        duplicatedKeyFn,

        this.duplicatedKeyFn?=?isFunction(duplicatedKeyFn)???duplicatedKeyFn?:?(config)?=>?`${config.method}${config.url}`;

        添加請求

        /**

        ?* 將請求添加到pendingAjax

        ?* @param {Object} config

        ?*/

        addPendingAjax(config)?{

        ??//?是否需要取消重復的請求

        ??if?(!this.cancelDuplicated)?return

        ??const?veryConfig?=?config.veryConfig?||?{};

        ??const?duplicatedKey?=?JSON.stringify({

        ????duplicatedKey:?veryConfig.duplicatedKey?||?this.duplicatedKeyFn(config),

        ????type:?REQUEST_TYPE.DUPLICATED_REQUEST,

        ??});

        ??config.cancelToken?=?config.cancelToken?||?new?axios.CancelToken((cancel)?=>?{

        ????// 如果pendingAjax中不存在當前請求,添加進去

        ????if?(duplicatedKey?&&?!this.pendingAjax.has(duplicatedKey))?{

        ??????this.pendingAjax.set(duplicatedKey,?cancel);

        ????}

        ??});

        }

        這里面我們可以使用duplicatedKey字段來讓用戶對單一請求自定義重復的標識?;蛘呖梢允褂靡粋€函數(shù)duplicatedKeyFn統(tǒng)一的讓用戶自定義重復的標識

        刪除請求

        /**

        ???* 從pendingAjax中刪除請求

        ???* @param {Object} config

        ???*/

        ??removePendingAjax(config)?{

        ????//?是否需要取消重復的請求

        ????if?(!this.cancelDuplicated)?return

        ????const?veryConfig?=?config.veryConfig?||?{};

        ????const?duplicatedKey?=?JSON.stringify({

        ??????duplicatedKey:?veryConfig.duplicatedKey?||?this.duplicatedKeyFn(config),

        ??????type:?REQUEST_TYPE.DUPLICATED_REQUEST,

        ????});

        ????// 如果pendingAjax中存在當前請求, 取消當前請求并將其刪除

        ????if?(duplicatedKey?&&?this.pendingAjax.has(duplicatedKey))?{

        ??????const?cancel?=?this.pendingAjax.get(duplicatedKey);

        ??????cancel(duplicatedKey);

        ??????this.pendingAjax.delete(duplicatedKey);

        ????}

        ??}

        封裝好了, 我們在哪里使用呢?肯定是在請求開始之前和請求完成之后使用。

        在請求之前

        // 攔截請求

        this.axios.interceptors.request.use((config)?=>?{

        ??//?在請求開始之前檢查先前的請求

        ??this.removePendingAjax(config);

        ??// 將當前請求添加到pendingAjax

        ??this.addPendingAjax(config);

        ??// ...

        });

        在請求完成之后去掉該請求

        // 攔截響應

        this.axios.interceptors.response.use(response?=>?{

        ??removePending(response)

        ??return?response

        },?error?=>?{

        ??// ...

        })

        到現(xiàn)在已經完成了該有的功能, 但是取消請求的錯誤我們不該返回給用戶。所以:

        (err)?=>?{

        //?類型是否為重復請求

        let?isDuplicatedType;

        try?{

        ??const?errorType?=?(JSON.parse(error.message)?||?{}).type

        ??isDuplicatedType?=?errorType?===?REQUEST_TYPE.DUPLICATED_REQUEST;

        }?catch?(error)?{

        ??isDuplicatedType?=?false

        }

        if?(isDuplicatedType)?return;

        }

        我們在請求完成之后的err里面做一個判斷,判斷如果當前請求是取消的類型,我們就不返回給用戶錯誤的提示信息。

        總結

        至此,完成了我們的封裝。完成的pr地址:(https://github.com/verymuch/very-axios/pull/1)。本文測試npm包的項目地址:(https://github.com/shuliqi/my-project-of-axios)

        ??愛心三連擊

        1.看到這里了就點個在看支持下吧,你的點贊,在看是我創(chuàng)作的動力。

        2.關注公眾號程序員成長指北,回復「1」加入高級前端交流群!「在這里有好多 前端?開發(fā)者,會討論?前端 Node 知識,互相學習」!

        3.也可添加微信【ikoala520】,一起成長。

        “在看轉發(fā)”是最大的支持

        瀏覽 14
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            超碰在线大香蕉 | 天天做天天爱天天做 | 午夜伦情电午夜伦情电影8090 | 欧美性猛交| 18禁女扒开腿免费视频爽 | 天天综合天天做 | 少妇交换俱乐部 | 欧美成人性影院 | 操逼小黄片 | 日批视频大全 |