2012-11-21 44 views
10

我有一個場景,我需要從Node.js/Express RESTful API返回一個非常大的對象,轉換爲JSON字符串。Streaming/Piping JSON.stringify Node.js/Express中的輸出

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

但是,這看起來不是很好。具體來說,它在我的測試機器上工作良好,有1-2個客戶端連接,但我懷疑當許多客戶端同時請求大型JSON對象時,此操作可能會導致內存使用率降低。

我一直在尋找一個異步JSON庫,但the only one I found似乎有問題(具體來說,我得到一個[RangeError])。不僅如此,它還在一個大塊中返回字符串(例如,整個字符串調用一次回調,這意味着內存佔用不會減少)。

我真正想要的是JSON.stringify函數的完全異步管道/流式版本,因此它可以在數據直接打包到流中時寫入數據...因此可以節省我的內存佔用空間和以同步方式使用CPU。

+0

創建了一個流,將對象作爲字符串寫入到蒸汽,最後只是管流水庫。 – wayne

回答

9

理想情況下,您應該按照原樣流式傳輸數據,而不是將所有內容都緩衝到一個大對象中。如果你不能改變這個,那麼你需要將stringify分成更小的單位,並允許主事件循環使用setImmediate來處理其他事件。示例代碼(我假設的主要對象有很多的頂級性能,並利用它們拆分工作):

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

很好的實施,謝謝! –

+0

不錯,但是這不會忽略obj頂層的鍵名和對象細節嗎? – Paul

+0

是的,你是對的。我會更新代碼 –

5

這聽起來像你想要Dominic Tarr的JSONStream。顯然,有一些程序集需要將它與express進行合併。但是,如果您正在嘗試將一個對象序列化(Stringify),那麼將該工作分成塊可能並不能真正解決問題。流式傳輸可能會減少內存佔用量,但不會減少所需的「工作量」總量。

+0

它可能不會減少工作總量,但隨着時間的推移分配(通過process.nextTick分離)意味着CPU不會掛鉤。 –

+2

注意:process.nextTick現在在執行事件循環之前執行。使用'setImmediate'。 – CoolAJ86