成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

結(jié)合promise與websocket的發(fā)布/訂閱模式實(shí)踐

vincent_xyb / 2756人閱讀

摘要:結(jié)合與的發(fā)布訂閱模式實(shí)踐本文初衷最近恰好在公司做了一個(gè)聊天室系統(tǒng),所以在系統(tǒng)中做了一下對(duì)進(jìn)行的化改造,所以想寫篇文章總結(jié)一下,如果大家有什么更好的方法或者心得感悟,歡迎交流技術(shù)??紤]到對(duì)并沒什么本質(zhì)影響,所以本文就不涉及了業(yè)務(wù)場(chǎng)景基于的聊天

結(jié)合promise與websocket的發(fā)布/訂閱模式實(shí)踐 本文初衷

最近恰好在公司做了一個(gè)聊天室系統(tǒng),所以在系統(tǒng)中做了一下對(duì)websocket進(jìn)行的promise化改造,所以想寫篇文章總結(jié)一下,如果大家有什么更好的方法或者心得感悟,歡迎交流

技術(shù)棧

dva + protobuf
考慮到protobuf對(duì)websocket并沒什么本質(zhì)影響,所以本文就不涉及了

業(yè)務(wù)場(chǎng)景

基于websocket的聊天室系統(tǒng)

開發(fā)痛點(diǎn)

可能存在按順序觸發(fā)的請(qǐng)求
eg. 刪除req---確認(rèn)刪除rsp---刷新頁(yè)面req---刷新頁(yè)面rsp
但由于并非所有的刪除操作后都會(huì)刷新頁(yè)面,所以考慮是不是可以使用發(fā)布訂閱模式來模擬類似promise的流式操作

存在同一類型請(qǐng)求短時(shí)間內(nèi)多次觸發(fā)時(shí),如何尋找每一條回復(fù)信息的發(fā)射源,考慮可以使用promise池+唯一識(shí)別碼token來實(shí)現(xiàn)

由于dva的異步操作是基于redux-saga的,所以如果可以用promise完成與websocket的互動(dòng),那么對(duì)于effects中使用yield控制異步流程,也會(huì)是一個(gè)很好的體驗(yàn)

實(shí)現(xiàn)原理

首先,這一套系統(tǒng)的一切前提是請(qǐng)求的唯一標(biāo)識(shí)符token,前端發(fā)送給服務(wù)器之后,服務(wù)器必須要把這個(gè)token跟數(shù)據(jù)放在一起發(fā)回來才行

本系統(tǒng)的實(shí)現(xiàn)原理是

對(duì)websocket的send方法進(jìn)行封裝
發(fā)送階段
1. send執(zhí)行時(shí),先生成一個(gè)promise,及其唯一token
2. 將promise的resolve, reject,token,及其他需要的信息放入一個(gè)對(duì)象,然后推入一個(gè)promise池中
3. 執(zhí)行websocket的send方法
4. return 這個(gè)promise

接收階段
1. 收到回復(fù)消息時(shí),先從promise池中對(duì)token進(jìn)行匹配
2. 根據(jù)回復(fù)的狀態(tài)決定執(zhí)行resolve或reject
3. 其他需要的操作
實(shí)現(xiàn)代碼
// 每一個(gè)實(shí)例都只能open一條socket線路,用鎖機(jī)制防止重復(fù)open
// 本例中不使用心跳檢測(cè),為了方便,只要close是非主動(dòng)觸發(fā)且前端能捕捉到的(如瀏覽器主動(dòng)斷開,服務(wù)器主動(dòng)斷開),都會(huì)進(jìn)行自動(dòng)重連
export class MyWebSocket {
    constructor(url) {
        this.url = url;
    
        // close來源判斷及后續(xù)操作
        this.closeConfig = {
            resolve: null,
            closing: false
        }
        // promise池
        this.promisePool = [];
    }
    
    tokenCheck(req, rsp) {
    // 此處根據(jù)自己的數(shù)據(jù)結(jié)構(gòu)進(jìn)行tokenCheck的判斷,返回一個(gè)boolean
    }
    
    open() {
        return new Promise((resolve, reject) => {
            if (typeof this._websocket === "undefined") {
                this._websocket = new WebSocket(this.url);
                this._websocket.open = (e) => {
                    resolve({e, ws: this});
                };
                this._websocket.onerror = (e) => {
                    reject(e);
                }
            }
            this._websocket.onclose = (e) => {
                // 非主動(dòng)close
                if (!this.closeConfig.closing) {
                    console.log("reconnect");     
                    // 對(duì)應(yīng)的重連操作     
                }
                // 若手動(dòng)close,恢復(fù)初始狀態(tài)
                this.closeConfig.closing = false;
            }
            
            this._websocket.onmessage = (e) => {
                this.promisePool = this.promisePool.filter((item) => {
                if (this.tokenCheck(req, rsp) {
                  req.resolve(rsp);
                  return false;
                }
                return true;
              })
            };
        });
    }
    
    close() {
        this.closeConfig.closing = true;
        this._websocket.close();        
    }
    // token包含在content中
    send(name, content) {
        return new Promise((resolve, reject) => {
          this.promisePool.push({
            content,
            resolve,
            reject,
            name
          });
          this._websocket.send({name, content});
    });
}

大概流程就是這樣,具體的樣例如下

*test () {
    const ws = new MyWebSocket("www.mywebsocket.com");
    yield ws.open();
    yield ws.send(.....).then(()=>{...});
    yield ws.send(.....).then(()=>{...});
}

本文呢大概就是這么多了,如果有什么錯(cuò)誤或者遺漏的地方還請(qǐng)大家多多指教

v0.0.2

采取了評(píng)論大佬的建議,將promise池從數(shù)組改為對(duì)象,直接將token做為key,查詢起來也非常方便

export class MyWebSocket {
    constructor(url) {
        this.url = url;
    
        // close來源判斷及后續(xù)操作
        this.closeConfig = {
            resolve: null,
            closing: false
        }
        // promise池
        this.promisePool = {};
    }
    
    tokenCheck(req, rsp) {
    // 此處根據(jù)自己的數(shù)據(jù)結(jié)構(gòu)進(jìn)行tokenCheck的判斷,返回一個(gè)boolean
    }
    
    open() {
        return new Promise((resolve, reject) => {
            if (typeof this._websocket === "undefined") {
                this._websocket = new WebSocket(this.url);
                this._websocket.open = (e) => {
                    resolve({e, ws: this});
                };
                this._websocket.onerror = (e) => {
                    reject(e);
                }
            }
            this._websocket.onclose = (e) => {
                // 非主動(dòng)close
                if (!this.closeConfig.closing) {
                    console.log("reconnect");     
                    // 對(duì)應(yīng)的重連操作     
                }
                // 若手動(dòng)close,恢復(fù)初始狀態(tài)
                this.closeConfig.closing = false;
            }
            
            this._websocket.onmessage = (e) => {         
                const key = e.content.token;    
                const req = this.promisePool[key]
                req.resolve(e);
                delete this.promisePool[key];
            };
        });
    }
    
    close() {
        this.closeConfig.closing = true;
        this._websocket.close();
    }
    // token包含在content中
    send(name, content) {
        return new Promise((resolve, reject) => {
          this.promisePool[content.token] = {
            content,
            resolve,
            reject,
            name
          };
          this._websocket.send({name, content});
    });
}

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/94995.html

相關(guān)文章

  • 前端知識(shí)點(diǎn)

    摘要:原理對(duì)處理函數(shù)進(jìn)行延時(shí)操作,若設(shè)定的延時(shí)到來之前,再次觸發(fā)事件,則清除上一次的延時(shí)操作定時(shí)器,重新定時(shí)。在目標(biāo)發(fā)出內(nèi)容改變的事件后,直接接收事件并作出響應(yīng)。首先是目標(biāo)的構(gòu)造函數(shù),他有個(gè)數(shù)組,用于添加觀察者。 關(guān)于排序 js中sort函數(shù)的底層實(shí)現(xiàn)機(jī)制? js中sort內(nèi)置多種排序算法,是根據(jù)要排序數(shù)的亂序程度來決定使用哪一種排序方法。V8 引擎 sort 函數(shù)只給出了兩種排序 Inse...

    wums 評(píng)論0 收藏0
  • GraphQL java工程化實(shí)踐

    摘要:我在工程實(shí)踐中直接使用類作為對(duì)應(yīng)實(shí)體類的。因此我的結(jié)論是,此庫(kù)并不適用于我的工程實(shí)踐。工程實(shí)踐中對(duì)其應(yīng)用方式的考慮在的官方教程中建議針對(duì)每請(qǐng)求創(chuàng)建新的實(shí)例,查詢請(qǐng)求結(jié)束則實(shí)例們的生命周期結(jié)束。 因?yàn)樽约簩戇^基于react的前端應(yīng)用,因此一看到GraphQL就被深深吸引,真是直擊痛點(diǎn)??!服務(wù)端開發(fā)一直是基于java, Spring的,因此開始研究如何在現(xiàn)有工程框架下加入graphql的支...

    MSchumi 評(píng)論0 收藏0
  • 2019年7-8月份前端面試題

    摘要:站點(diǎn)接收到請(qǐng)求后,對(duì)請(qǐng)求進(jìn)行驗(yàn)證,并確認(rèn)是受害者的憑證,誤以為是無辜的受害者發(fā)送的請(qǐng)求。函數(shù)內(nèi)部語(yǔ)句返回的值,會(huì)成為方法回調(diào)函數(shù)的參數(shù)。 記錄我最近面試缺漏的知識(shí)點(diǎn) css 1.bootstrap如何實(shí)現(xiàn)手機(jī)PC端自適應(yīng) 媒體查詢 2.flex布局 父容器:(記得常用屬性) display:flex flex-direction: row | row-reverse | column ...

    shevy 評(píng)論0 收藏0
  • 什么是 HTML 5?

    摘要:該區(qū)域代表可以被所控制的畫布。那么現(xiàn)在第二個(gè)問題,識(shí)別該文檔,這或許不是大部分用戶的需求,但小部分用戶并不意味著人數(shù)少。因此一個(gè)基于的請(qǐng)求于標(biāo)準(zhǔn)內(nèi)提出。 前言 作為程序員,技術(shù)的落實(shí)與鞏固是必要的,因此想到寫個(gè)系列,名為 why what or how 每篇文章試圖解釋清楚一個(gè)問題。 這次的 why what or how 主題:現(xiàn)在幾乎所有人都知道了 HTML5 ,那么 H5 到底相...

    zhaofeihao 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<