2017-07-18 88 views
2

相對較新的node.js和異步處理方式,到目前爲止我已經能夠使用promise讀取使用fs readFile的文件,但我沒有'沒有任何運氣讓zlib Gunzip工作。寫作的CoffeeScript:Node.js - Gunzip已讀文件異步問題

promisifyRun(fs, 'readFile', filepath, 'utf-8') 
    .then (file) -> 
     promisifyRun(zlib, 'Gunzip', file) 
     .then (data) -> 
      console.log "HELLO" 
      return data 
    .catch respondError res 

promisfyRun是有前途的一個單一的功能(我沒有寫出來,但它的工作)。我已經設法成功地使用它的fs.readFile組件,就像這樣:

promisifyRun(fs, 'readFile', filepath, 'utf-8') 
    .then (data) -> 
     return data 
    .catch respondError res 

這只是正常,等待要打開的文件,然後繼續。 'data'包含文件的主體。我認爲它應該是一個非常合理的擴展,以納入gunzip組件,但到目前爲止這一直是一個挑戰。

我看了幾個npm gunzip模塊。似乎最有趣的那個是gunzip-maybezlib.Gunzip(我在這裏嘗試)。

對於這種特殊情況下的錯誤消息已:

"Unhandled rejection Error: Can't set headers after they are sent."

我認爲這是相關的過程中就已經有其異步的完成事業

更新 - 全堆棧跟蹤:

Unhandled rejection Error: Can't set headers after they are sent. at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:357:11) at ServerResponse.header (/Users/jcook/project/node_modules/express/lib/response.js:725:10) at ServerResponse.send (/Users/jcook/project/node_modules/express/lib/response.js:170:12) at ServerResponse.json (/Users/jcook/project/node_modules/express/lib/response.js:256:15) at ServerResponse.send (/Users/jcook/project/node_modules/express/lib/response.js:158:21) at /Users/jcook/project/.tmp/lib/util.js:40:22 at tryCatcher (/Users/jcook/project/node_modules/bluebird/js/release/util.js:16:23) at Promise._settlePromiseFromHandler (/Users/jcook/project/node_modules/bluebird/js/release/promise.js:512:31) at Promise._settlePromise (/Users/jcook/project/node_modules/bluebird/js/release/promise.js:569:18) at Promise._settlePromise0 (/Users/jcook/project/node_modules/bluebird/js/release/promise.js:614:10) at Promise._settlePromises (/Users/jcook/project/node_modules/bluebird/js/release/promise.js:689:18) at Async._drainQueue (/Users/jcook/project/node_modules/bluebird/js/release/async.js:133:16) at Async._drainQueues (/Users/jcook/project/node_modules/bluebird/js/release/async.js:143:10) at Immediate.Async.drainQueues (/Users/jcook/project/node_modules/bluebird/js/release/async.js:17:14) at runCallback (timers.js:672:20) at tryOnImmediate (timers.js:645:5) at processImmediate [as _immediateCallback] (timers.js:617:5)

+0

什麼是完整的堆棧跟蹤? – LEQADA

+0

請發送發送標題的代碼。你的'util。tryCatcher'(或使用它的代碼)可能是問題。 – Bergi

回答

1

當你看到Can't set headers after they're sent,它幾乎始終是因爲您的請求處理程序在端點響應後仍在執行,其中的IME與不等待回調完成的代碼有99%的關聯。

首先,您不否認承諾的使用承諾的許多好處。

promisifyRun(fs, 'readFile', filepath, 'utf-8') 
.then (file) -> 
    // Just return another promise here. 
    return promisifyRun(zlib, 'Gunzip', file) 
.then (data) -> 
    console.log "HELLO" 
    return data 
.catch respondError res 

其次,您從回調中運行return data。我的猜測是,你正試圖在另一側用一個返回值,像這樣:

run =()-> 
    promisifyRun(fs, 'readFile', filepath, 'utf-8') 
    .then (file) -> 
    // Just return another promise here. 
    return promisifyRun(zlib, 'Gunzip', file) 
    .then (data) -> 
    console.log "HELLO" 
    return data 
    .catch respondError res 

myData = run() 

這不起作用,因爲什麼東西被從承諾返回是異步的。您需要處理響應異步:

run =()-> 
    promisifyRun(fs, 'readFile', filepath, 'utf-8') 
    .then (file) -> 
    // Just return another promise here. 
    return promisifyRun(zlib, 'Gunzip', file) 
    // We remove the rest of the function, 
    // so it just returns the promise above. 

run().then (data)-> 
    console.log data 

一旦CS 2.0的土地,你就可以使用ES6異步/ AWAIT:

data = await run() 
+0

這太棒了!感謝這樣一個徹底的答覆,我剛剛瞭解到承諾,我認爲這讓我有點頭腦圍繞他們的預期效用。 – cookersjs

0

一個簡單而有效的方法是使用fs和zlib模塊我節點:

fs.createReadStream('./file.gz') 
    .pipe(zlib.createGunzip()) 
    .pipe(res); 

如果你的情況,你有文件內容只有緩衝區,然後zlib.gunzip足夠:

zlib.gunzip(buffer, (err, gunzippedBuffer) => { 
    // ... 
}); 

https://nodejs.org/dist/latest-v6.x/docs/api/zlib.html#zlib_zlib_gunzip_buf_options_callback

+0

我試過了第一個選項,但是我收到一條消息說'TypeError:fs.​​createReadStream(...)。pipe不是函數' – cookersjs