2016-04-22 59 views
0

當涉及到語法錯誤時,爲什麼本地Promise的行爲就像try/catch?Promises爲什麼捕獲語法錯誤?

當您需要按順序執行一些異步操作時,Promise在流量控制中顯然具有價值。但是,爲每個承諾實施自己的錯誤處理實施方案的必要性有時會讓他們很難處理。

採取以下代碼:

asdf 
 

 
let one = new Promise((resolve, reject) => { 
 
    asdf 
 
}).catch(err => { 
 
    console.log(err) 
 
    console.log(err.stack) 
 
})

第一語法錯誤產生一個典型的瀏覽器誤差和與18個條目的堆棧跟蹤。承諾的版本有4.

所以我的問題是,當編寫規範並在本地實現它時,他們是否保留了承諾的用戶空間實現的try/catch類功能,以便它可以用於流控制但保留標準錯誤處理?

+3

因爲這不是一個語法錯誤,但在未來的參考誤差(可能)發生的歷史。 – Bergi

+1

請注意,錯誤是ReferenceErrors而不是SyntaxErrors。後者不能被捕捉,因爲引擎不能很好地理解執行腳本。但是,'asdf'是一個有效的標識符,單獨訪問一個變量是一個有效的語句。所以,解析器找不到任何問題。 –

+0

不確定這是否合適的重複:[爲什麼用於拒絕JS中的承諾的例外](http://stackoverflow.com/q/21616432/1048572)如果您的問題是關於其他問題,請評論。 – Bergi

回答

3

當代碼加載並且仍然是拋出的異常時,JavaScript解析器將拋出實際的語法錯誤。基本上,當解析器決定不能正確解析代碼時,那時就沒有別的事情要做。它會放棄並停止解析其餘的代碼。

它是承諾會處理的運行時錯誤(發生在代碼執行期間,而不是加載/解析期間)。

通過規範,.then()承諾處理程序是「投擲安全」,這意味着它們將拋出的異常轉化爲被拒絕的承諾。這是因爲這些處理程序總是異步的,異步回調中拋出的異常相當無用,因爲它們不能被調用代碼捕獲,因爲調用代碼不再位於堆棧上,並且只能通過回調來通知調用代碼。異常最終會進入一些異步基礎架構,其中沒有調用代碼可以攔截或處理它們。因此,他們決定將異常轉換爲拒絕,以便可以使用承諾的所有正常拒絕處理和錯誤傳播。

而且,因爲調用代碼無法捕獲異常,所以如果承諾沒有執行此操作,那麼在幾乎每個.then()處理程序中都必須執行自己的try/catch操作,以確保您捕獲任何東西出錯了。因此,它可以節省大量額外的代碼,並且可以很容易地確保所有異步異常都能被正確捕獲,並將錯誤傳播回調用代碼。簡而言之,一旦你習慣了它,它是非常有用的,因爲無論如何,無處可去的異常無用,我會說設計者通過決定捕捉異常並使它們有用是非常好的選擇。僅供參考,您仍然可以在.then()處理程序中執行您自己的嘗試/捕捉,並根據需要自行執行任何操作。

0

原因是因爲當你在處理異步進程時,你沒有沒有人來捕捉你的錯誤。 以前的調用堆棧消失了。

機智:

function simulateAsyncError() { 
    try { 
    setTimeout(function() { throw new Error("Nobody caught me"); }, 1); 
    console.log("I have set the future error."); 
    } catch (err) { console.log("I caught it!"); } 
} 

simulateAsyncError(); 
// "I have set the future error." 
// Uncaught Error: "Nobody caught me" 

承諾是關於包裝的是,和處理這一點。

+0

我完全被downvote困惑,因爲這個例子完全回答了原帖的底部提出的問題。 – Norguard

1

Promises不捕獲典型的語法錯誤,這些錯誤發生在分析/編譯時。你的例子不是SyntaxError(解析器不理解你的代碼),它是一個ReferenceError(解釋器/運行時無法找到你指定的標識符)。

Uncaught ReferenceError: asdf is not defined 

如果有字面代碼語法錯誤,它會被抓。這是我們應該期待的:如果它不能解析代碼,它不知道你甚至已經創建了一個承諾。

let one = new Promise((resolve, reject) => { 
    foo bar baz 
}).catch(err => { 
    // ignore error 
}); 
Uncaught SyntaxError: Unexpected identifier 

請注意,如果您使用eval生成在運行時(從無極-使用代碼的角度看)語法錯誤,它會被抓住。區別不在於錯誤的JavaScript對象類型之間,區別在於編譯時和運行時錯誤之間。

let one = new Promise((resolve, reject) => { 
    eval("foo bar baz"); 
}).catch(err => { 
    console.log("Captured error:", err); 
}) 
Captured error: SyntaxError: Unexpected identifier