2016-11-01 4 views
0

Kontext: Ich verwende einen Websocket, um eine Verbindung zu einem Netty-Server für meine Website herzustellen. Ich habe benutzerdefinierte Methoden und die Art, wie ich mit Nachrichten umgehen, ist auch benutzerdefiniert.Wie kann ich die Änderungserkennung für eine bestimmte Methode eines WebSockets abbrechen?

Wenn eine Nachricht, die ich senden möchte, zu groß ist, werde ich sie in viele kleine Nachrichten teilen, so dass ein einzelner Socket "parallele" Nachrichten senden kann. Dieser Teil funktioniert gut

Problem: Jedes Mal, wenn ein ‚Nachrichtenteil‘ die websocket erreicht, geht es in einen ‚MessageDecoder‘ decodiert und in eine tatsächliche Nachricht verkettet werden, die (ich nehme an) zones.js Trigger eine seitenweite Änderungserkennung. Da dies so schnell geschieht, wie der Websocket die Nachrichtenteile verarbeiten kann, verlangsamt es die gesamte Anwendung auf einen Crawl, schlimmer noch, nichts an der Anwendung ändert sich jemals, bis die gesamte Nachricht abgeschlossen ist und dann die Callbacks aufgerufen werden (welche die verursachen die Veränderungen). Das Herunterladen einer Datei führt normalerweise zu 6000 Nachrichtenteilen, von denen nur die letzte jemals Änderungen an der Anwendung vornehmen kann.

Ich habe bereits versucht, blind hinzuzufügen 'this.zone.runOutsideAngular (() => {' auf den Code, aber ich konnte es nicht beheben. Ich verstehe nicht ganz, wo es anwendbar ist, da zu verwenden Ich verstehe nicht ganz, wenn zones.js entscheidet, die Änderungserkennung auszulösen.Im folgenden Code wird es einen Kommentar geben, der den EINZIGEN Codeabschnitt angibt, der eine Änderungserkennung EVER auslösen sollte:

OBS: Ich könnte möchte später einen 'die Nachricht mit ID zzz erhalten xxx yyy Teile' Zähler (um eine Download-Leiste), so dass auch eine Änderungserkennung auslösen müsste, aber hoffentlich ist es möglich, sicherzustellen, dass nur diejenigen, die zuhören Diese Methode/Variable prüft auf Änderungen und nicht auf die gesamte Seite

Code:

import { Injectable, NgZone } from '@angular/core'; 

declare var MessageDecoder: any; 
declare var MessageEncoder: any; 
declare var GetMessageTranslator: any; 
declare var TextDecoder: any; 
declare var DataStream: any; 
declare var StatusCheck: any; 
@Injectable() 
export class ConnectionService { 
    public connection: any; 
    private status: boolean; 
    public ping: number; 
    public errorState: number; 
    public interval: number; 

    constructor(private zone: NgZone) { 
     this.startAutoConnect(); 
    } 

    public getState() { 
     if (this.connection == undefined) { 
      return "offline"; 
     } 
     if (this.errorState > new Date().getTime()) { 
      return "error"; 
     } 
     if (this.connection.readyState != WebSocket.OPEN) { 
      return "offline"; 
     } else { 
      if (this.status) { 
       return "loggedIn"; 
      } else { 
       return "connected"; 
      } 
     } 
    } 
    autoConnectHandle: any; 
    waitForSocketConnection(socket, callback) { 
     setTimeout(
      function() { 
       if (socket.readyState === 1) { 
        if (callback !== undefined) { 
         callback(); 
        } 
        return; 
       } else { 
        this.waitForSocketConnection(socket, callback); 
       } 
      }, 5); 
    }; 
    onOpen1 = function() { 
     this.aThis.onOpen(this.aThis); 
    } 
    onOpen = function() { 
     this.waitForSocketConnection(this.connection,() => { 
      clearInterval(this.autoConnectHandle); 
      this.autoConnectHandle = undefined; 
      var connection: any = this.connection; 
      var aThis: ConnectionService = this; 
      connection.onclose = function() { 
       aThis.startAutoConnect(); 
      } 
      connection.supersend = connection.send; 
      connection.send = function(message, callback, type) { 
       if (message.ID == undefined) { 
        message.configure(); 
        message.init(this); 
       } 
       if (this.promiseMap[message.getRequestID()] == undefined) { 
        this.promiseMap[message.getRequestID()] = { 
         type: type, 
         callback: callback, 
         complete: false 
        }; 
       } 
       message.writeToChannel(this); 
      } 
      connection.attr = {}; 
      connection.promiseMap = {}; 

      connection.onerror = function(error) { 
       this.errorState = new Date().getTime() + 1500; 
       console.error('WebSocket Error ' + error); 
      }; 
      connection.channelRead = function(message) {//called by the message decoder after the message is complete 
       console.log("got: " + message.getClass()); 
       var promisse = this.promiseMap[message.getRequestID()]; 
       if (promisse != undefined) { 
        if (promisse.complete) { 
         return; 
        } else { 
         if (promisse.type == message.getClass() || promisse.type == undefined) { 
          if (promisse.callback != undefined) { 
           //THIS SHOULD TRIGGER THE CHANGE DETECTION, ANYTHING ELSE MEANS THAT IT WAS 
           //A MESSAGE THAT DON'T CARE ABOUT THE RESULT, SO NOTHING WILL CHANGE BECAUSE 
           //OF IT 
           promisse.callback(message); 
          } 
          promisse.complete = true; 
          delete this.promiseMap[message.getRequestID()]; 
         } else if (message.getClass() == "NullServerMessage") { 

         } 
        } 
        var answer = message.processAnswer(this); 
        if (answer.getClass() != "NullServerMessage") { 
         console.log("sent: " + answer.getClass()); 
         this.send(answer); 
        } 
       } 
      } 
      connection.decoder = new MessageDecoder(); 
      connection.encoder = new MessageEncoder(); 

      connection.onmessage = (e) => { 
       //I believe this is triggering the excess of change detections 
       var arrayBuffer; 
       var fileReader = <any>new FileReader(); 
       fileReader.onload = function() { 
        connection.decoder.decode(connection, new DataStream(this.result), undefined) 
       }; 
       fileReader.readAsArrayBuffer(e.data); 
      }; 
      aThis.interval = setInterval(() => new function() { 
       connection.pingCounter = new Date().getTime(); 
       connection.send(new StatusCheck(), function(message) { 
        aThis.status = message.status; 
        aThis.ping = new Date().getTime() - connection.pingCounter; 
       }); 
      }, 1000); 
      connection.send(new GetMessageTranslator(), function(message) { 
       connection.decoder.translator = message.map; 
       connection.encoder.translator = message.map; 
       connection.encoder.translator.getKeyByValue = function(value) { 
        for (var prop in this) { 
         if (this.hasOwnProperty(prop)) { 
          if (this[prop] === value) 
           return prop; 
         } 
        } 
       } 

      }); 
     }); 
    } 

    startAutoConnect() { 
     if (this.connection) { 
      this.connection.close(); 
      if (this.interval != undefined) { 
       clearInterval(this.interval); 
       this.interval = undefined; 
      } 
      this.connection = undefined; 
     } 
     var connection: any; 
     var aThis: ConnectionService = this; 
     if (!this.autoConnectHandle) { 
      this.autoConnectHandle = setInterval(() => new function() { 
       if (this.connection == undefined) { 
        aThis.connection = connection = new WebSocket('ws://localhost:80/websocket'); 
        connection.aThis = aThis; 
        connection.onopen = aThis.onOpen1; 
        connection.onerror = function(error) { 
         aThis.startAutoConnect(); 
        }; 
       } 
      }, 1500); 
     } 
    } 

} 

Antwort

0

Ich glaube, ich habe es, durch

Wechsel
constructor(private zone: NgZone) { 
    this.startAutoConnect(); 
} 

zu

constructor(private zone: NgZone) { 
    this.zone.runOutsideAngular(() => { 
     this.startAutoConnect(); 
    }); 
} 

Dies machte damit nichts als Reaktion auf die websocket Aktualisierung wurde nennt neben der Ping-Zähler, und das Ergebnis von meinem Websocket-Nachrichten wurde nur aktualisiert, sobald der Ping-Zähler auch aktualisiert, was mich dazu bringt, dass es tatsächlich funktionierte, waren die Nachrichten n ot die Änderungserkennung auszulösen, sorta wie ich wollte.

Das Problem ist, dass das ursprüngliche Problem von allem, was während des Downloads sehr langsam wird, persistent ist, so dass dies nie der Grund dafür war.

Wechsel

    if (promisse.type == message.getClass() || promisse.type == undefined) { 
         if (promisse.callback != undefined) { 
          //THIS SHOULD TRIGGER THE CHANGE DETECTION, ANYTHING ELSE MEANS THAT IT WAS 
          //A MESSAGE THAT DON'T CARE ABOUT THE RESULT, SO NOTHING WILL CHANGE BECAUSE 
          //OF IT 
          promisse.callback(message); 
         } 
         promisse.complete = true; 
         delete this.promiseMap[message.getRequestID()]; 

zu

    if (promisse.type == message.getClass() || promisse.type == undefined) { 
         if (promisse.callback != undefined) { 
          this.aThis.zone.run(() => { 
           promisse.callback(message); 
          }); 
         } 
         promisse.complete = true; 
         delete this.promiseMap[message.getRequestID()]; 

machte die Änderungserkennung jedes Mal eine Meldung vollständig war geschehen und Fertigbearbeitung des Rückrufs.

Verwandte Themen