連繫promise與websocket的宣布/定閱形式實踐

連繫promise與websocket的宣布/定閱形式實踐

本文初志

近來恰幸虧公司做了一個聊天室體系,所以在體系中做了一下對websocket舉行的promise化革新,所以想寫篇文章總結一下,假如人人有什麼更好的要領或許心得感悟,迎接交換

手藝棧

dva + protobuf
斟酌到protobuf對websocket並沒什麼實質影響,所以本文就不觸及了

營業場景

基於websocket的聊天室體系

開發痛點

  1. 能夠存在按遞次觸發的要求
    eg. 刪除req—確認刪除rsp—革新頁面req—革新頁面rsp
    但因為並不是統統的刪除操縱后都邑革新頁面,所以斟酌是否是能夠運用宣布定閱形式來模仿相似promise的流式操縱
  2. 存在統一範例要求短時間內屢次觸發時,怎樣尋覓每一條復興信息的發射源,斟酌能夠運用promise池+唯一識別碼token來完成
  3. 因為dva的異步操縱是基於redux-saga的,所以假如能夠用promise完成與websocket的互動,那末關於effects中運用yield掌握異步流程,也會是一個很好的體驗

完成道理

起首,這一套體系的統統條件是要求的唯一標識符token,前端發送給服務器以後,服務器必須要把這個token跟數據放在一同發回來才行

本體系的完成道理是

對websocket的send要領舉行封裝
發送階段
1. send實行時,先天生一個promise,及其唯一token
2. 將promise的resolve, reject,token,及其他須要的信息放入一個對象,然後推入一個promise池中
3. 實行websocket的send要領
4. return 這個promise

吸收階段
1. 收到復興音訊時,先從promise池中對token舉行婚配
2. 依據復興的狀況決議實行resolve或reject
3. 其他須要的操縱

完成代碼

// 每個實例都只能open一條socket線路,用鎖機制防備反覆open
// 本例中不運用心跳檢測,為了輕易,只需close黑白主動觸發且前端能捕捉到的(如瀏覽器主動斷開,服務器主動斷開),都邑舉行自動重連
export class MyWebSocket {
    constructor(url) {
        this.url = url;
    
        // close泉源推斷及後續操縱
        this.closeConfig = {
            resolve: null,
            closing: false
        }
        // promise池
        this.promisePool = [];
    }
    
    tokenCheck(req, rsp) {
    // 此處依據本身的數據結構舉行tokenCheck的推斷,返回一個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) => {
                // 非主動close
                if (!this.closeConfig.closing) {
                    console.log('reconnect');     
                    // 對應的重連操縱     
                }
                // 若手動close,恢復初始狀況
                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(()=>{...});
}

本文呢也許就是這麼多了,假如有什麼毛病或許脫漏的處所還請人人多多指教

v0.0.2

採取了批評大佬的發起,將promise池從數組改成對象,直接將token做為key,查詢起來也異常輕易

export class MyWebSocket {
    constructor(url) {
        this.url = url;
    
        // close泉源推斷及後續操縱
        this.closeConfig = {
            resolve: null,
            closing: false
        }
        // promise池
        this.promisePool = {};
    }
    
    tokenCheck(req, rsp) {
    // 此處依據本身的數據結構舉行tokenCheck的推斷,返回一個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) => {
                // 非主動close
                if (!this.closeConfig.closing) {
                    console.log('reconnect');     
                    // 對應的重連操縱     
                }
                // 若手動close,恢復初始狀況
                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});
    });
}
    原文作者:Heptagon
    原文地址: https://segmentfault.com/a/1190000014873336
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞