2017-01-13 56 views
0

在我工作的公司裏,一切都是用回調完成的。我們正在開始編寫具有大代碼所依賴的承諾的小組件。我們開始遇到麻煩。如何用回調包裝承諾?

function getSomething() { 
    return Promise.resolve('hello') 
} 

function test(cb) { 
    getSomething() 
    .then(string => { 
    a.s 
    cb(null, string) 
    }, error => cb(error)) 
} 

test((error, result) => { 
    console.log(error) 
    console.log(result) 
    a.s 
}) 

這是一個簡單的問題示例。在這個代碼中,因爲a不存在,它會拋出一個警告UnhandledPromiseRejectionWarning並終止進程。控制檯日誌永遠不會到達。

背後的邏輯是,如果發生錯誤會觸發catch回調。

function test(cb) { 
    getSomething() 
    .then(string => { 
    // a.s 
    cb(null, string) 
    }, error => cb(error)) 
    .catch(error => cb(error)) 
} 

我被建議在承諾鏈的末尾使用顯式捕獲。問題是如果在回調中拋出一個錯誤,回調會觸發兩次。

感謝您的任何幫助。

+0

如何整個包住再放入一試,並在catch錯誤? –

+1

那麼..那麼可能你不應該在'then'階段使用'onRejected'回調,而只需鏈接一個'.catch()'就像你在第二個代碼段中做的那樣。 – Redu

+0

@Redu,將此評論移至答案,因爲這是正確的答案。 @ AlvaroOrtiz的第二段代碼將錯誤處理程序'cb'連接兩次。 – DaveS

回答

1

.then(onFulfilled, onRejected) 

.then(onFullfilled) 
.catch(onRejected) 

之間細微的差別第一個將無法趕上onFullFilled回調,而第二個會中拋出的錯誤。所以可能你不應該在當時的階段使用onRejected回調,而只是像你在第二個片段中那樣鏈接.catch()

+0

即使我刪除'then'中的第二個處理程序並且發生錯誤,它仍然會再次在catch語句中調用處理程序。 –

+0

@Alvaro Ortiz這很正常。 '.catch()'函子是下游的,它會捕獲前一階段拋出的第一個錯誤。 – Redu

0

你可以讓調用CB前誤差比CB內發生的那些區別對待的代碼在then部分分開。不要在那裏調用cb,而是返回字符串值,以便可以在鏈接的then方法中使用它。在那裏你可以使用成功和失敗之間的切換。那樣只會在那裏調用cb

現在,如果通過調用CB發生錯誤時,你能趕上與最終.catch,但你不會把CB了,但也許只是輸出一些東西,或級聯錯誤,或做任何你想在這種情況下做。

這裏有三個使用案例演示:

  1. 沒有錯誤
  2. 在(第一)錯誤then
  3. CB

function getSomething() { 
 
    return Promise.resolve('hello'); 
 
} 
 

 
function test(testNo, cb) { 
 
    getSomething() 
 
    .then(string => { 
 
    if (testNo == 2) a.s; 
 
    return string; // don't call cb yet 
 
    }) 
 
    .then(cb.bind(null, null), cb) // now call it -- mutually exclusive with error case 
 
    .catch(error => { // catch any errors not yet captured -- i.e. in cb 
 
     console.log('test ' + testNo + ': error occurred in success callback'); 
 
    }); 
 
} 
 

 
for (let testNo = 1; testNo <= 3; testNo++) { 
 
    test(testNo, (error, result) => { 
 
    if (error) 
 
     console.log('callback for test ' + testNo + ' error:', error.message); 
 
    else 
 
     console.log('callback for test ' + testNo + ' success:', result); 
 
    if (testNo == 3) a.s; 
 
    }); 
 
}
錯誤

0

在您的代碼片段中會發生什麼情況:當您的then()中發生錯誤時,返回被拒絕的承諾。 因爲在此之後你還沒有任何處理程序,這個被拒絕的承諾不會被處理,並且(幸運的是)會彈出。

你主要有兩種方法可以解決這個問題: 您既可以添加其他catch()then()方法這樣

function test(cb) { 
    getSomething() 
    .then(string => { 
    a.s 
    cb(null, string) 
    }) 
    .catch(e => cb) //this catch() handles whatever rejected promise 
        //comes out of then() or from the earlier promise 
} 

在該方案中,可能發生之後,你被調用兩次回調的情況下,執行cb(null,string)時拋出錯誤。在這種情況下,在回調中需要一個警衛來區分不同的錯誤代碼,以確定它是來自getSomething()還是來自cb(null,string)。

或者你可以這樣

function test(cb) { 
    getSomething() 
    .then(string => { 
    try{ 
     a.s 
     cb(null, string) 
    } catch(e) { 
     if(e.message == "callback error" { 
      //do what you want to do to with a callback error 
     } else { 
      //do whatever you want to do with other errors from your catch block 
     } 
    } 
    }, error => cb(error)) 
} 

在此方案中您then()處理程序中添加一個傳統的try/catch塊,你可以把守衛區分catch塊不同的錯誤的原因,並呼籲回調只有一次。但是,您需要另一個處理機制來處理您的錯誤。一個簡單的可能性就是默默吞下新的錯誤,但這可能是一個不好的解決方案。

這就是異步編程的問題,當堆棧上下文丟失,直到最終執行回調時,不會有錯誤冒泡到中央處理程序。

乾杯, 菲利克斯