2017-09-04 2 views
1

Dans mon code (une application de surveillance), j'ai besoin d'appeler périodiquement le serveur avec un objet XMLHttpRequest sous la forme d'appels chaînés. Chaque appel prend exactement 15 secondes, ce qui est chronométré par le serveur car il fournit plusieurs résultats partiels au cours de cette période (HTTP 100 Continue). Immédiatement après la fin de l'appel en cours, le gestionnaire d'événement onreadystatechange de l'objet XMLHttpRequest actuel doit créer et lancer la requête suivante (avec une nouvelle instance), de sorte que la communication avec le serveur reste presque transparente. De la façon dont cela fonctionne, chaque appel retient le contexte d'objet de l'appelant dans la pile, comme il s'agit d'une page qui doit rester ouverte pendant des jours, la pile ne cesse de croître sans que le garbage collector puisse réclamer les données . Voir la trace de la pile suivante:Éviter la fuite d'appel de chaîne XMLHttpRequest

Stack trace over a couple of minutes

Je ne peux pas utiliser des minuteries (setInterval ou ces) pour lancer la requête suivante. Il devrait être lancé depuis l'intérieur de la fin de la précédente. Les données du serveur doivent arriver le plus rapidement possible, et malheureusement les navigateurs trament des timers quand une page n'est pas mise au point. Comme je l'ai dit, il s'agit d'une application de surveillance destinée à être toujours active dans les moniteurs secondaires des utilisateurs (rarement mise au point). Je dois également faire face à des délais d'attente HTTP et d'autres types d'erreurs qui déraillent de la séquence de 15 secondes. Il devrait toujours y avoir un et un seul canal ouvert avec le serveur.

Ma question est de savoir s'il est possible d'éviter de conserver tout le contexte de la pile lors de la création d'un objet XMLHttpRequest. Même l'appel de la méthode click() sur un objet DOM conserve la pile/le contexte en vie. Même les promesses semblent garder le contexte.

Je ne peux pas non plus utiliser les Websockets, car le serveur ne les prend pas en charge.

MISE À JOUR:

Il est plus complexe, vous pouvez acheter en substance, il est comme:

var xhttpObjUrl; 
var xhttpObj; 

onLoad() { 
    loadXMLDoc(pollURL + "first=1", true); 
} 

function loadXMLDoc(url, longtout) { 
    xhttpObjUrl = url; 
    xhttpObj = new XMLHttpRequest(); 
    xhttpObj.open(method, url, true); 
    xhttpObj.onprogress = progress; 
    xhttpObj.onloadend = progress; 
    xhttpObj.ontimeout = progress; 
    if (commlog) consolelog("loadXMLDoc(): url == " + dname); 
    xhttpObj.send(""); 
} 

function progress() { 
    if (!xhttpObj) return; 
    var state = xhttpObj.readyState; 
    var status; 
    var statusText; 
    if (state == 4 /* complete */ || state == 3 /* partial content */) { 
     try { 
      status = xhttpObj.status; 
      statusText = xhttpObj.statusText; 
      if (status == 200) parseServerData(); 
     } catch (err) { 
      status = 500; 
      statusText = err; 
     } 
     if (state == 4 || status != 200) { 
      /* SERVER TERMINATES THE CONNECTION AFTER 15 SECONDS */ 
      /* ERROR HANDLING REMOVED */ 
      var obj = xhttpObj; 
      xhttpObj = undefined; 
      abortRequest(obj); 
      obj = false; 
      RequestEnd(); 
     } 
    } 
} 

function RequestEnd(error) { 
    var now = (new Date).getTime(); 
    var msdiff = now - lastreqstart; 
    var code = function() { loadXMLDoc(pollURL + 'lastpoint=' + evtprev.toString() + '&lastevent=' + evtcurrent.toString()); return false; }; 
    if (msdiff < 1000) addTimedCheck(1, code); /** IGNORE THIS **/ 
    else code(); 
} 
+0

sans code, la réponse est "peut-être" –

+0

Ajout d'un code snip. –

Répondre

0

J'ai résolu mon problème à l'aide d'un travailleur Web. Le travailleur terminerait XMLHttpRequest chaque fois et enverrait à la page un message avec les données collectées. Ensuite, lorsque la page termine le traitement des données, il envoie un message au travailleur pour lancer une nouvelle requête. Ainsi, ma page n'aurait pas de retards indésirables entre les demandes, et il n'y a pas de pile constamment en construction. En cas d'erreur, je mettrais fin au travail et en créerais un nouveau, juste au cas où.