簡體   English   中英

在promise鏈中吞噬了異常

[英]Exception gets swallowed in promise chain

當Parse for React Native中的一系列promise中拋出異常時,我注意到發生了一些非常奇怪的事情。 承諾鏈永遠不會解決,永遠不會拒絕,並且永遠不會拋出異常。 它只是默默地消失。

這是重新創建問題的示例代碼:

// Replacing this with Promise.resolve() prints the error.
// Removing this stage prints the error.
Parse.Promise.as()
  // Removing this stage causes a red screen error.
  .then(function() {
    // Replacing this with Parse.Promise.as() causes a red screen error.
    return Promise.resolve();
  })
  .then(function () {
    throw new Error("There was a failure");
  })
  .then(function () { console.log("Success")}, function (err) { console.log(err) });

正如您從評論中看到的那樣,它似乎只發生在這個特定的事件序列中。 刪除一個階段,或者交換一個原生JS承諾的Parse承諾,會導致事情再次發生。 (在我的實際代碼中,“Promise.resolve()”階段實際上是對返回promise的本機iOS方法的調用。)

我知道Parse承諾的行為與A +兼容的承諾完全不同 (參見https://stackoverflow.com/a/31223217/2397068 )。 實際上,在此代碼段之前調用Parse.Promise.enableAPlusCompliant()會導致捕獲並打印異常。 但我認為Parse promises和原生JS承諾可以安全地一起使用。

為什么這個異常會默默地消失?

謝謝。

除了引用答案中提供的技術原因外,供您考慮:

符合承諾

符合ES6 / A +標准的Promise實例共享:

  1. 當承諾得到解決時,其結算的狀態和價值是不可變的。
  2. 諾言不能兌現承諾。
  3. 然后,使用promise(或其他可能的)對象作為參數調用隨后注冊的“fulfill”偵聽器。
  4. 通過注冊的監聽器then是造成他們要執行已經運行完代碼后在自己的線程異步執行。
  5. 無論聽眾是否注冊了回叫,承諾都會得到解決(“履行”或“被拒絕”),

    • 偵聽器的返回值是用來實現 解決其返回的承諾, then登記
    • 監聽器throw的值(使用throw )用於拒絕then注冊返回的promise,和
  6. 使用Promise實例解析的promise將自身與作為參數提供的最終已解決狀態和promise的值同步。 (在ES6標准中,這被描述為“鎖定”)。

  7. 使用不是 Promise實例的thenable對象解決的promise將根據需要跳過同步:如果最初使用thenable來“解析”自己的thenable,則Promise promise將與最近的'thenable'重新同步提供。 使用A + promises時,跳過一個新的可以與之同步並不會發生,因為它們永遠不會使用一個可對象的對象調用“已完成”的偵聽器。

不合規的承諾

不符合承諾的潛在特征包括對象

  • 允許改變承諾的既定狀態,
  • 使用promise參數調用當時'履行'的監聽器,
  • 通過解析或拒絕承諾的代碼同步調用一個偵聽器,用於“已完成”或“已拒絕”狀態,
  • 在then調用中注冊的偵聽器拋出異常后,不拒絕then返回的promise。

互通性

Promise.resolve可用於通過靜態值來解決其返回的promise,可能主要用於測試。 然而,它的主要目的是隔離不合規承諾的副作用。 Promise.resolve( thenable)返回的承諾將展示上述1-7的所有行為,並且不會出現任何不符合行為的行為。

恕我直言我建議只在環境中使用非A + promise對象,並根據創建它們的庫的文檔。 非兼容的thenable可用於直接解析A + promise(這是Promise.resolve所做的),但是對於行為的完全可預測性,它應該在任何其他使用之前使用Promise.resolve( thenable)包裝在Promise對象中。

注意我試圖測試Parse承諾的A +合規性,但它似乎沒有提供構造函數。 這使得“幾乎”或“完全”A +合規性的主張難以量化。 感謝zangw指出可能會將拒絕的promise作為一個偵聽器返回,作為拋出異常的替代方法。

為什么這個例外消失了?

Parse默認情況下不會捕獲異常,並且promises會吞下它們。

解析是不是100%的承諾/ A +兼容,但盡管如此它試圖吸收那些從返回thenables then回調。 並且它既不捕獲異常也不異步執行自己的回調。

你在做什么,不能夠被復制then使用

var p1 = new Parse.Promise();
var p2 = new Parse.Promise();

// p2 should eventually settle and call these:
p2._resolvedCallbacks = [function (res) { console.log("Success") }];
p2._rejectedCallbacks = [function (err) { console.log(err) }];

function handler() {
    throw new Error("There was a failure");
}
// this is what the second `then` call sets up (much simplified):
p1._resolvedCallbacks = [function(result) {
    p2.resolve(handler(result)); // throws - oops
}];

// the native promise:
var p = Promise.resolve();
// what happens when a callback result is assimilated:
if (isThenable(p))
    p.then(function(result) {
        p1.resolve(result);
    });

問題是p1.resolve是同步的,並立即在p1上執行回調 - 這反過來會拋出。 通過在p2.resolve調用之前p2.resolvep2將永遠保持未決狀態。 例外冒泡並變成完成p1.resolve() -現在拋出在回調於天然then方法。 本機promise實現捕獲異常並拒絕then返回的promise,但是無處不在。

默默?

如果您的“本機”承諾實現支持未處理的拒絕警告,您應該能夠在被拒絕的承諾中看到異常。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM