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 取消重復(fù)請(qǐng)求

        共 5256字,需瀏覽 11分鐘

         ·

        2021-01-13 17:34

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

        在我們web開(kāi)發(fā)過(guò)程中,很多地方需要我們?nèi)∠貜?fù)的請(qǐng)求。但是哪種場(chǎng)合需要我們?nèi)∠??我們?nèi)绾稳∠??帶著這些問(wèn)題我們閱讀本文。

        閱讀完本文,你將了解以下內(nèi)容:

        • 需要取消重復(fù)請(qǐng)求的場(chǎng)景

        • 我們?nèi)绾稳∠貜?fù)請(qǐng)求

        • axios如何取消重復(fù)的請(qǐng)求

        • 封裝axios

        • 如何給開(kāi)源的項(xiàng)目提供源碼

        • 如何在本地調(diào)試npm包

        提出問(wèn)題

        最近做的項(xiàng)目中,用的用戶(hù)經(jīng)常遇到這樣的問(wèn)題:

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

        • 用戶(hù)點(diǎn)擊了一次提交按鈕,接口沒(méi)有很快響應(yīng),導(dǎo)致頁(yè)面沒(méi)辦法做邏輯語(yǔ)句判斷的提示。用戶(hù)覺(jué)得可能沒(méi)提交上,便會(huì)快速又點(diǎn)了按鈕幾次。如果后端沒(méi)有去重的判斷,就會(huì)導(dǎo)致數(shù)據(jù)中有很多條重復(fù)的數(shù)據(jù)。

        這些問(wèn)題給用戶(hù)的體驗(yàn)是很不友好的。那么取消無(wú)用的請(qǐng)求是很有必要的。

        解決思路

        我們用的請(qǐng)求庫(kù)是axios。那么我們可以在請(qǐng)求的時(shí)候攔截請(qǐng)求判斷當(dāng)前的請(qǐng)求是否重復(fù),如果重復(fù)我們就取消當(dāng)前的請(qǐng)求。大致的實(shí)現(xiàn)過(guò)程如下:

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

        我們這個(gè)解決思路有了,但是axios如何取消請(qǐng)求的呢?我們先來(lái)了解下

        axios 如何取消請(qǐng)求

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

        • 第一種方法

          通過(guò)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?{

          ????// 處理錯(cuò)誤

          ??}

          });


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

          ??name:?'new name'

          },?{

          ??cancelToken:?source.token

          })


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

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


        • 第二種方式

          通過(guò)傳遞一個(gè) executor 函數(shù)到 CancelToken 的構(gòu)造函數(shù)來(lái)創(chuàng)建 cancel token

          const?CancelToken?=?axios.CancelToken;

          let?cancel;


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

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

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

          ????cancel?=?c;

          ??})

          });


          // 取消請(qǐng)求

          cancel();


        封裝axios

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

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

        準(zhǔn)備工作

        由于同事已經(jīng)封裝了axios并且已經(jīng)開(kāi)源了。那么我貢獻(xiàn)代碼的方式主要有兩種:

        • 代碼倉(cāng)庫(kù)的管理者給我們添加這個(gè)倉(cāng)庫(kù)的寫(xiě)入權(quán)限,如果這樣,我們就可以直接提push。

        • 如果我們沒(méi)有權(quán)限(大多數(shù)情況)。我們使用經(jīng)典的fork & pull request 的方式來(lái)提交代碼。

        我們采用的第二種方式。我們?nèi)?very-axios(https://github.com/verymuch/very-axios) 把代碼fork到自己的倉(cāng)庫(kù)(如果你還沒(méi)有自己的github,需要自己注冊(cè)下哦)。


        那么你回到自己的github倉(cāng)庫(kù)下面就會(huì)看有一個(gè)一摸一樣的項(xiàng)目


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

        現(xiàn)在已經(jīng)有本地的代碼了,但是我們?nèi)绾伪镜鼗{(diào)試npm包呢?那就需要npm link

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


        之后我們會(huì)得到

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

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

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

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

        我們?cè)?span style="margin-right: 2px;margin-left: 2px;border-width: 1px;border-style: solid;border-color: rgb(225, 225, 232);padding: 2px 4px;font-size: 12px;font-family: monospace;color: rgb(221, 17, 68);background-color: rgb(247, 247, 249);border-radius: 2px;word-break: break-all;overflow-wrap: break-word;">my-project-of-axios中的HelloWorld.vue文件中做列子。

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


        開(kāi)始封裝

        準(zhǔn)備工作完成了, 那我們開(kāi)始封裝的事情。根據(jù)我們之前的思路。我們采用axios 如何取消請(qǐng)求的第一種方式。

        聲明一個(gè)Map。用來(lái)存儲(chǔ)每個(gè)請(qǐng)求的 標(biāo)識(shí) 和 取消的函數(shù)

        // 存儲(chǔ)每個(gè)請(qǐng)求的標(biāo)識(shí)和取消的函數(shù)

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

        自定一個(gè)字段來(lái)讓用戶(hù)自己決定是否需要取消重復(fù)的請(qǐng)求

        // 是否取消重復(fù)的請(qǐng)求

        cancelDuplicated?=?false,

        自定一個(gè)字段來(lái)讓用戶(hù)是否有全局的統(tǒng)一的設(shè)置重復(fù)標(biāo)識(shí)的函數(shù)。如果沒(méi)有設(shè)置全局的統(tǒng)一的函數(shù),則默認(rèn)是請(qǐng)求的methodurl作為重復(fù)的標(biāo)識(shí)

        // 生成重復(fù)標(biāo)識(shí)的方式

        duplicatedKeyFn,

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

        添加請(qǐng)求

        /**

        ?* 將請(qǐng)求添加到pendingAjax

        ?* @param {Object} config

        ?*/

        addPendingAjax(config)?{

        ??//?是否需要取消重復(fù)的請(qǐng)求

        ??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中不存在當(dāng)前請(qǐng)求,添加進(jìn)去

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

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

        ????}

        ??});

        }

        這里面我們可以使用duplicatedKey字段來(lái)讓用戶(hù)對(duì)單一請(qǐng)求自定義重復(fù)的標(biāo)識(shí)?;蛘呖梢允褂靡粋€(gè)函數(shù)duplicatedKeyFn統(tǒng)一的讓用戶(hù)自定義重復(fù)的標(biāo)識(shí)

        刪除請(qǐng)求

        /**

        ???* 從pendingAjax中刪除請(qǐng)求

        ???* @param {Object} config

        ???*/

        ??removePendingAjax(config)?{

        ????// 是否需要取消重復(fù)的請(qǐng)求

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

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

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

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

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

        ????});

        ????// 如果pendingAjax中存在當(dāng)前請(qǐng)求, 取消當(dāng)前請(qǐng)求并將其刪除

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

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

        ??????cancel(duplicatedKey);

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

        ????}

        ??}

        封裝好了, 我們?cè)谀睦锸褂媚??肯定是在?qǐng)求開(kāi)始之前和請(qǐng)求完成之后使用。

        在請(qǐng)求之前

        // 攔截請(qǐng)求

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

        ??//?在請(qǐng)求開(kāi)始之前檢查先前的請(qǐng)求

        ??this.removePendingAjax(config);

        ??// 將當(dāng)前請(qǐng)求添加到pendingAjax

        ??this.addPendingAjax(config);

        ??// ...

        });

        在請(qǐng)求完成之后去掉該請(qǐng)求

        // 攔截響應(yīng)

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

        ??removePending(response)

        ??return?response

        },?error?=>?{

        ??// ...

        })

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

        (err)?=>?{

        //?類(lèi)型是否為重復(fù)請(qǐng)求

        let?isDuplicatedType;

        try?{

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

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

        }?catch?(error)?{

        ??isDuplicatedType?=?false

        }

        if?(isDuplicatedType)?return;

        }

        我們?cè)谡?qǐng)求完成之后的err里面做一個(gè)判斷,判斷如果當(dāng)前請(qǐng)求是取消的類(lèi)型,我們就不返回給用戶(hù)錯(cuò)誤的提示信息。

        總結(jié)

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


        瀏覽 46
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        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>
            男女午夜 | 丰满少妇夜夜爽爽高潮水网站 | 国产绿奴调教91 | 爽 好大 快 奶水声音91 午夜激情视频网站 | 成人 视频免费观看网站 | 伦理视频在线观看夫妻板国产 | 先锋影音一区二区 | 久久视频热 | 国产丰满岳乱妇在线观看 | 两男一女3p又黄又猛 |