<kbd id="5sdj3"></kbd>
<th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>

    小白必看:前端競(jìng)態(tài)條件的產(chǎn)生與解決

    共 2551字,需瀏覽 6分鐘

     ·

    2022-05-25 13:09


    點(diǎn)擊上方?前端陽(yáng)光,關(guān)注公眾號(hào)

    回復(fù)加群,加入技術(shù)交流群交流群



    • 一、什么是異步請(qǐng)求的競(jìng)態(tài)問(wèn)題

    • 二、如何解決異步請(qǐng)求的競(jìng)態(tài)問(wèn)題

      • 2.1 交互層面解決

      • 2.2 取消請(qǐng)求

      • 2.3 拋棄無(wú)用的請(qǐng)求

    • 參考資料


    一、什么是異步請(qǐng)求的競(jìng)態(tài)問(wèn)題

    首先,先闡述一下什么是競(jìng)態(tài)問(wèn)題,現(xiàn)在我有一個(gè)前端頁(yè)面如下如圖,它的功能是根據(jù)用戶的查詢條件來(lái)請(qǐng)求和展示列表數(shù)據(jù)。

    網(wǎng)絡(luò)正常的情況下我們直接請(qǐng)求并展示數(shù)據(jù)就可以了,完全沒(méi)有技術(shù)的難度。但是當(dāng)網(wǎng)絡(luò)不穩(wěn)定時(shí)就會(huì)出現(xiàn)查詢條件和頁(yè)面展示結(jié)果不一致的情況。我們舉例說(shuō)明:

    • 首先用戶在描述輸入框輸入“快樂(lè)”,然后點(diǎn)擊查詢 , 這次我們稱為第一次請(qǐng)求
    • 緊接著用戶在描述輸入框輸入“悲傷”,然后點(diǎn)擊查詢,這次我們稱為第二次請(qǐng)求

    網(wǎng)絡(luò)波動(dòng)時(shí),如果第二次請(qǐng)求的結(jié)果比第一次請(qǐng)求先返回,頁(yè)面上描述輸入框展示的是 “悲傷”,但是頁(yè)面展示的列表數(shù)據(jù)卻是第一次請(qǐng)求查詢出的“快樂(lè)”對(duì)應(yīng)的結(jié)果。

    二、如何解決異步請(qǐng)求的競(jìng)態(tài)問(wèn)題

    這里我整理出解決這個(gè)問(wèn)題的幾種方法供大家參考(下文的代碼主要用來(lái)展示思路,并未經(jīng)過(guò)測(cè)試)。

    2.1 交互層面解決

    在發(fā)起請(qǐng)求后,我們添加全局的 loading 遮罩,或者 禁用****查詢按鈕 ,這樣的話,我們?cè)谝粋€(gè)請(qǐng)求未完成前不能發(fā)送新的請(qǐng)求,這樣就能解決了。

    但是這個(gè)方法有幾個(gè)缺點(diǎn):

    • 阻斷交互
    • 觸發(fā)查詢的動(dòng)作很多樣,如回車鍵等。這種情況下需要考慮的點(diǎn)會(huì)比較多
    • 要說(shuō)服產(chǎn)品、交互的同事(如果你特別能 Battle 需求,就忽略這一條)

    2.2 取消請(qǐng)求

    如果我們能夠在每次請(qǐng)求時(shí),都先取消上一次的請(qǐng)求就能確保最終的查詢結(jié)果和查詢的條件是一致的。

    2.2.1 axios

    我們以 axios 的 cancellation 舉例:

    const?CancelToken?=?axios.CancelToken;
    let?source

    //?請(qǐng)求的函數(shù)
    funtion?query?(keyword)?{
    ??if?(source)?{
    ????source.cancel('取消請(qǐng)求');
    ??}
    ??source?=?CancelToken.source();

    ????return?axios.post('/list',?{
    ????keyword
    ??},?{
    ????cancelToken:?source.token
    ??}).catch(function?(thrown)?{
    ????//?區(qū)別處理取消請(qǐng)求和請(qǐng)求錯(cuò)誤
    ????if?(axios.isCancel(thrown))?{
    ??????//?取消請(qǐng)求的邏輯
    ????}?else?{
    ??????//?請(qǐng)求錯(cuò)誤
    ????}
    ??});
    }

    上面的代碼中,在每次查詢前都使用 source.cancel() 取消了上一次的請(qǐng)求。

    2.2.2 可取消的 Promise

    當(dāng)然,不是每個(gè)人都會(huì)使用 axios 作為請(qǐng)求庫(kù),一個(gè)通用的做法是定制一個(gè)可取消的 Promise 來(lái)封裝請(qǐng)求。(注意:Promise 是不能取消的,這里取消指的是手動(dòng)把 Promise 設(shè)為 rejected 狀態(tài) ),代碼如下:

    let?doCancel

    //?請(qǐng)求的函數(shù)
    funtion?query?(keyword)?{
    ??if?(doCancel)?{
    ????//?設(shè)置上一次的?Promise?設(shè)為?rejected?狀態(tài)
    ????doCancel('取消請(qǐng)求');
    ??}
    ??return?new?Promise(function(resolve,?reject)?{
    ????//?掛載?reject?方法
    ????doCancel?=?reject
    ????const?xhr?=?new?XMLHttpRequest();
    ????xhr.on("load",?resolve);
    ????xhr.on("error",?reject);
    ????xhr.open("POST",?'/list',?true);

    ????//?發(fā)送請(qǐng)求條件,這里未作處理
    ????xhr.send(null);
    ??}).catch(function?(thrown)?{
    ????//?區(qū)別處理取消請(qǐng)求和請(qǐng)求錯(cuò)誤
    ????if?(axios.isCancel(thrown))?{
    ??????//?取消請(qǐng)求的邏輯
    ????}?else?{
    ??????//?請(qǐng)求錯(cuò)誤
    ????}
    ??});
    }

    如果你不想折騰,這里推薦使用 bluebird 的 cancellation 功能

    2.3 拋棄無(wú)用的請(qǐng)求

    最后一種處理方式最為比較容易理解:只處理當(dāng)前查詢條件對(duì)應(yīng)請(qǐng)求結(jié)果,其它的查詢條件的結(jié)果我們都認(rèn)為是無(wú)用的請(qǐng)求,對(duì)于無(wú)用的請(qǐng)求我們?cè)诨卣{(diào)函數(shù)里不處理就可以了。

    //?請(qǐng)求標(biāo)記
    let?gobalReqID?=?0

    //?請(qǐng)求的函數(shù)
    funtion?query?(keyword)?{
    ??gobalReqID++
    ????let?curReqID?=?gobalReqID
    ????return?axios.post('/list',?{
    ????keyword
    ??}).then(res?=>?{
    ????//?對(duì)比閉包內(nèi)的?curReqID?是否和?gobalReqID?一致
    ????if?(gobalReqID?===?curReqID)?{
    ????????return?res
    ????}?else?{
    ????????return?Promse.reject('無(wú)用的請(qǐng)求')
    ????}
    ??})
    }

    上面的代碼是使用一個(gè)自增的 reqID 和 閉包特性來(lái)判斷是否是無(wú)用的請(qǐng)求的,對(duì)于比較簡(jiǎn)單的查詢條件,我們可以直接判斷查詢條件的是否一致即可。

    參考資料

    作者:有朝 鏈接:https://juejin.cn/post/6970710521104302110



    往期推薦


    優(yōu)秀文章匯總:https://github.com/Sunny-lucking/blog

    內(nèi)推:https://www.yuque.com/peigehang/kb

    技術(shù)交流群


    我組建了技術(shù)交流群,里面有很多?大佬,歡迎進(jìn)來(lái)交流、學(xué)習(xí)、共建?;貜?fù)?加群?即可。后臺(tái)回復(fù)「電子書(shū)」即可免費(fèi)獲取?27本?精選的前端電子書(shū)!回復(fù)內(nèi)推,可內(nèi)推各廠內(nèi)推碼



    ???“分享、點(diǎn)贊在看” 支持一波??


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

    手機(jī)掃一掃分享

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

    手機(jī)掃一掃分享

    分享
    舉報(bào)

    <kbd id="5sdj3"></kbd>
    <th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>
    日韩黄色小视频 | 四虎8848精品成人免费网站 | 插逼视频免费 | 美女操屄| 男女拍拍视频免费 |