2012-11-21 17 views
10

Ho uno scenario in cui ho bisogno di restituire un oggetto molto grande, convertito in una stringa JSON, dalla mia API RESTful Node.js/Express.Streaming/Piping Output JSON.stringify in Node.js/Express

res.end(JSON.stringify(obj)); 

Tuttavia, questo non sembra scalare bene. In particolare, funziona perfettamente con la mia macchina di prova con 1-2 client che si connettono, ma ho il sospetto che questa operazione potrebbe uccidere l'utilizzo della CPU della CPU & quando molti client richiedono contemporaneamente oggetti JSON di grandi dimensioni.

Mi sono messo in cerca di una libreria JSON asincrona, ma l'the only one I found sembra avere un problema (in particolare, ho un [RangeError]). Non solo, ma restituisce la stringa in un'unica grande porzione (ad esempio, la richiamata viene chiamata una sola volta con l'intera stringa, il che significa che l'impronta della memoria non viene diminuita).

Quello che voglio veramente è una versione di piping/streaming completamente asincrona della funzione JSON.stringify, in modo che scriva i dati non appena viene impacchettata direttamente nello stream ... risparmiando così sia il footprint di memoria, sia da consumando la CPU in modo sincrono.

+0

si crea un flusso, scrivere l'oggetto come stringa nel vapore, e, infine, solo il tubo del flusso di res. – wayne

risposta

9

Idealmente, è necessario eseguire lo streaming dei dati così come sono e non memorizzare tutto in un unico oggetto di grandi dimensioni. Se non si riesce a cambiare questo, è necessario interrompere la stringa in unità più piccole e consentire al loop eventi principale di elaborare altri eventi utilizzando setImmediate. Esempio di codice (io assumere oggetto principale ha un sacco di proprietà di alto livello e li usa per dividere il lavoro):

function sendObject(obj, stream) { 
    var keys = Object.keys(obj); 
    function sendSubObj() { 
     setImmediate(function(){ 
      var key = keys.shift(); 
      stream.write('"' + key + '":' + JSON.stringify(obj[key])); 
      if (keys.length > 0) { 
      stream.write(','); 
      sendSubObj(); 
      } else { 
      stream.write('}'); 
      } 
     }); 
    }) 
    stream.write('{'); 
    sendSubObj(); 
} 
+0

Bella implementazione, grazie! –

+0

Bello, ma questo non omette i nomi dei tasti e il dettaglio dell'oggetto dal livello superiore di obj? – Paul

+0

Sì, hai ragione. Aggiornerò il codice –

5

Sembra che tu voglia il JSONStream di Dominic Tarr. Ovviamente, è necessario un assemblaggio per unire questo con express.

Tuttavia, se la CPU tenta di serializzare (Stringify) un oggetto, la suddivisione del lavoro in blocchi potrebbe non risolvere il problema. Lo streaming può ridurre l'ingombro della memoria, ma non riduce la quantità totale di "lavoro" richiesto.

+0

Potrebbe non ridurre la quantità totale di lavoro, ma distribuirla nel tempo (separandola tramite process.nextTick) significa che la CPU non verrà acquisita. –

+2

Nota: process.nextTick viene eseguito prima di cedere al ciclo degli eventi. Usa 'setImmediate'. – CoolAJ86

Problemi correlati