2015-11-11 76 views
3

鑑於以下代碼:爲什麼不承諾異步操作拋出錯誤?

var fs = require('fs'); 

var asyncErrorPromise = new Promise(function(resolve) { 
    fs.readFile('does/not/exist.blah', function(fileError, content) { 
    if (fileError) throw fileError; 
    resolve(content); 
    }); 
}); 

asyncErrorPromise 
    .then(function(content) { 
    console.log('content received: ' + content); 
    }) 
    .catch(function(err) { 
    console.log('error received: ' + err.name); 
    }); 

我期望時,拋出(因爲我嘗試加載不存在的文件)將被無極捕獲和漏斗進入.catch()聲明fileError。所以最後我會得到這個輸出:error received: ENOENT

然而,當我運行此代碼,我得到以下代替:

if (err) throw err; 
      ^

Error: ENOENT: no such file or directory, open 'does/not/exist.blah' 
    at Error (native) 

所以未能逮住錯誤:它扔了,就像通常那樣,就好像它是一個承諾之外。

這是怎麼發生的?

我所能找到的關於Promise的所有內容都更關注錯誤被吞噬了,而不是這個問題,當它不需要的時候它會拋出!

以及應該如何我在這裏達到我的目的?我是否需要使用try-catch語句和reject處理程序?

+0

正如你所提到的,你需要抓住並拒絕/推遲承諾。任何未捕獲的異常都將由引擎處理並停止腳本。 – Baski

+0

你爲什麼要抓住錯誤?簡單地拒絕它 –

+1

你使用什麼承諾lib?在ES6中,在一個新的promise構造函數中拋出的錯誤應該隱含地拒絕這個promise,所以你的代碼應該工作,假設承諾實現是ES6 compat。 – ehynds

回答

2

使用promise不能捕獲異步回調函數中拋出的錯誤,因爲其上下文將丟失。在你使用Node的情況下,你將失去process.on('uncaughtException')處理程序中錯誤的上下文,並且回調將在事件隊列中作爲自己的事件運行,並帶有自己的上下文和範圍。

使用承諾,正確的解決方案將是reject的包裝承諾。

另一種方法是使用Domain對象(Domain documentation),但它正在等待棄用。使用domain,您可以維護上下文併爲您的錯誤註冊處理程序,如下所示。

var domain = require('domain'); 

var d = domain.create(); 

d.on('error', function(err){ 
    //Do something with your error 
}); 

d.run(function(){ 
    //Run your async code that might throw error 
});