連續同源異步操做隊列

問題的發現

來自同源的多個異步操做可能引發異步衝突問題,特別是在網絡請求時。同源操做產生了兩個ajax請求,它們的請求結果將用於渲染同一個區域,然而因爲網絡問題,先發出的請求後返回,致使最終獲得的界面是錯誤的。html

解決這個問題的最好辦法,是利用原生XHR的abort方法,在後一次操做時,將前一次操做引發的ajax請求給cancel掉。ios

可是在現實條件下,異步操做並不是都有cancel操做。js原生的Promise沒有,原生的fetch基於Promise也沒有。基於Promise的不少工具都沒有cancel操做。這種狀況下怎麼解決這個問題呢?git

其實方法是有的,就是直接丟棄Promise的推送,不執行它的resolve回調便可。這樣,雖然異步操做已經執行了,但不會對現有的環境形成任何反作用。(雖然這樣看上去浪費了異步操做這個資源。)github

問題的思考

如何來判斷是否要丟掉它的回調?咱們能夠建立一個隊列,每次產生一個異步操做時,就將它加入到隊列中,當隊列中存在操做對象時,每次只取最後一個,等待它推送結果,執行它的回調,排在它前面的操做所有丟棄掉。ajax

基於這樣的想法,我寫了一個工具。它爲異步操做建立隊列,並根據不一樣的場景實現不一樣的隊列操做形式。你能夠經過這裏閱讀它的源碼和文檔。它提供了4種可供選擇的場景,開發者根據本身的實際場景選擇使用其中的一種。npm

問題的解決

基於上述的思考,我最終發佈了deferer-queue,你能夠經過npm安裝這個包,在本身的項目中使用它。它的操做模式超級簡單,首先實例化一個queue對象,而後往這個queue push異步操做,異步操做被裝在一個函數中被push進隊列,它的回調函數必定是按照push的順序執行。axios

import DefererQueue from 'deferer-queue'

const queue = new DefererQueue()

const defer1 = () => new Promise((resolve, reject) => { ... })
const defer2 = () => axios.get(...)
const defer3 = async () => ...

queue.push(defer1).then(() => { console.log(1) })
queue.push(defer2).then(() => { console.log(2) })
queue.push(defer3).then(() => { console.log(3) })複製代碼

不管defer1-3中的誰,執行後誰先返回結果,控制檯輸出的結果永遠是1 2 3(defer都成功的前提下),由於deferer-queue設計的就是保證回調是按push順序執行。bash

要使用不一樣模式,只須要在實例化的時候,傳入一個options對象,將mode設置爲parallel/serial/switch/shift中的一個便可:網絡

const queue = new DefererQueue({
  mode: 'switch',
})複製代碼

其餘的用法同樣。這樣,你的隊列就會只採用最後一個push進隊列的defer的結果,即便你的隊列正在進行,只要有新的defer被push進去,那以前的全部操做都會被丟掉,隊列運行結果只取最後一個操做的結果。異步

關於具體的API使用細則,你能夠閱讀它的文檔。其中,利用axios的cancel能力那個地方很是有借鑑意義。

關於四種運行模式的詳細解釋,因爲圖片限制,請到個人博客進行閱讀。

相關文章
相關標籤/搜索