2015-05-06 42 views
1

我有這樣的要求處理程序,它看起來像這樣:如何儘早打破承諾鏈,在Express中發送錯誤?

router.post('/', function(req,res) { 
    var screencast; 
    var channel; 

    youtube.get(req.body.videoId).then(function(data) { 
    screencast = data.screencast; 
    channel = data.channel; 
    }).then(function() { 
    return connection.beginTransactionAsync(); 
    }).then(function() { 
    return connection.queryAsync('INSERT IGNORE INTO Channels SET ?', channel); 
    }).then(function() { 
    return connection.queryAsync('INSERT INTO Screencasts SET ?', screencast) 
    }).then(function() { 
    return connection.commit(); 
    }).error(function(e) { 
    connection.rollback(); 
    }); 
}); 

有時候我想打破諾言鏈早期併發送一個錯誤。這裏是我的嘗試:

router.post('/', function(req,res) { 
    var screencast; 
    var channel; 

    youtube.get(req.body.videoId).then(function(data) { 
    if (data === null) { 
     res.send('error: video does not exist.'); 
     return; 
    } 
    screencast = data.screencast; 
    channel = data.channel; 
    }).then(function() { 
    console.log('trace: starting transaction'); 
    return connection.beginTransactionAsync(); 
    }).then(function() { 
    return connection.queryAsync('INSERT IGNORE INTO Channels SET ?', channel); 
    }).then(function() { 
    return connection.queryAsync('INSERT INTO Screencasts SET ?', screencast) 
    }).then(function() { 
    return connection.commit(); 
    }).error(function(e) { 
    connection.rollback(); 
    }); 
}); 

雖然顯示錯誤,許鏈demonstrably不破;下一個函數被調用。

我的問題是,我該如何早點破壞承諾鏈發送錯誤?

東西,我試過是引入一個多個級別的縮進:

youtube.get(req.body.videoId).then(function(data) { 
    if (data === null) { 
    res.send('error: video does not exist.'); 
    return; 
    } 
    connection.beginTransactionAsync().then(function() { 
    return connection.queryAsync('INSERT IGNORE INTO Channels SET ?', channel); 
    }).then(... 

我發現這個工作然而,我擔心使用更多的嵌套,因爲我還需要檢查視頻是否已經存儲在數據庫中,在處理之前,需要兩個的縮進級別,也許更多。

我發現了另外兩個答案(one),但它們對我沒有幫助。我的問題特別與Bluebird和Express有關。

+0

不要認爲它是*破*,而是*分支*(如'if'語句),並且縮進感覺更加自然。作爲獎勵,如果你嵌套函數,你不需要那些醜陋的全局變量。 – Bergi

+0

我明顯是C#開發人員 - 自2012年以來,我們擁有'async'關鍵字 - 因此很難。但是,感謝您的評論。 –

+0

然後,您可能想要查看babel(具有'async'支持的ES6轉譯器)或Bluebirds'Promise.coroutine'。他們將所有'then'回調函數刪除,並允許您使用函數中的'return'。 – Bergi

回答

3

我想你只需要在你的承諾鏈上添加一個.catch的回調函數,當你遇到一個應該違背承諾的問題時,你需要添加一個.catch回調函數和throw

router.post('/', function(req,res) { 
    var screencast; 
    var channel; 

    youtube.get(req.body.videoId).then(function(data) { 
    if (data === null) { 
     throw new Error('video does not exist.'); 
    } 
    screencast = data.screencast; 
    channel = data.channel; 
    }).then(function() { 
    console.log('trace: starting transaction'); 
    return connection.beginTransactionAsync(); 
    }).then(function() { 
    return connection.queryAsync('INSERT IGNORE INTO Channels SET ?', channel); 
    }).then(function() { 
    return connection.queryAsync('INSERT INTO Screencasts SET ?', screencast) 
    }).then(function() { 
    return connection.commit(); 
    }).error(function(e) { 
    connection.rollback(); 
    }).catch(function(err){ 
    res.send("error: " + err); 
    }); 
}); 
+0

這是有問題的,OP需要拋出一個'Promise.OperationalError',以便事務回滾,或者你應該拋出一個泛型catch。在這裏,所有人都不是最好的主意。 –

+1

在我拋出錯誤的特定位置,不需要回滾,並且拋出'OperationalError'會被'error'處理程序捕獲,這將會回滾一個不存在的提交併且不會發送錯誤消息。但是,如果發生SQL庫中的潛在錯誤,或者OP想要在事務中間轉義promise鏈,那麼應該拋出一個'Promise.OperationalError',以便它可以被現有的'.error'處理程序捕獲並回滾交易。我錯過了什麼嗎? –