2013-02-10 63 views
0

對於異步編程,我還有點新意,我一直在想是否有更好的方法來完成我正在嘗試做的事情。在函數中使用多個回調結果的更優雅方式?

exports.content = function(req, res){ 
    OPID = req.params.id; 

    titles.findOne({postID: OPID}, function (err, post) { //function #1 
    if (err) throw(err); 

    readComment(OPID, function(comment){ //function #2 

     branchFilter.getBranches(function(branches){ //function #3 

     res.render('content', {title: post.title, content: post.body, OPID: post.postID, comments: comment, branches: branches}); 
     }) 
    }); 
    }); 
}; 

在這個例子中,我有三個嵌套函數,它們使用回調從其他模塊中檢索數據。我需要在res.render語句中包含所有這些數據。我想如果我繼續這種方法,我將需要更多的嵌套函數。有沒有更好的方法來做到這一點?

+2

[承諾](https://github.com/kriskowal/q)。 – 2013-02-10 16:52:41

+2

https://github.com/caolan/async – JohnnyHK 2013-02-10 16:57:38

回答

1

正如JohnnyHK所建議的,一個好的異步庫會幫助你解決這個問題。我也建議Caolan's async。您可以使用autoforEach的組合來解決幾乎任何異步問題,但如果運行時存在問題async可能不是最佳選擇。我想如下重寫代碼:

exports.content = function(req, res){ 
    OPID = req.params.id; 

    async.auto({ 
    post: function(next) { 
     titles.findOne({postID: OPID}, next); 
    }, 
    comment: function(next) { 
     readComment(OPID, function(comment){ next(null, comment); }); 
    }, 
    branches: function(next) { 
     branchFilter.getBranches(function(branches){ next(null, branches); }); 
    } 
    }, function(err, results) { 
    if(err) throw(err); 
    res.render('content', {title: results.post.title, content: results.post.body, OPID: results.post.postID, comments: results.comment, branches: results.branches}); 
    }); 
}; 

什麼auto確實是需要的功能的字典(與字典中的其他功能,可選的依賴 - 看到更多的異步自述),並將結果傳遞的字典第二個參數是「最終」功能。

如果任何的功能通過一個非空err到它的回調(第一個參數),它停止調用其它函數並立即去往errnull結果「最終」功能。

請注意,我必須通過branchescomment函數中的匿名函數。這是因爲auto與此async庫中的其他函數一樣,期望其回調的第一個參數是錯誤值,第二個參數是結果。

2

對你比如,有一個功能,只是得到的數據


看看http://callbackhell.com/給出瞭如何編寫使用 回調幹淨的代碼很好的概述。從該網站複製

姓名的功能下

下面是一個使用瀏覽器的請求,使一個AJAX請求到服務器的一些(亂)瀏覽器的JavaScript:

var form = document.querySelector('form') 
form.onsubmit = function(submitEvent) { 
    var name = document.querySelector('input').value 
    request({ 
    uri: "http://example.com/upload", 
    body: name, 
    method: "POST" 
    }, function(err, response, body) { 
    var statusMessage = document.querySelector('.status') 
    if (err) return statusMessage.value = err 
    statusMessage.value = body 
    }) 
} 

此代碼有兩個匿名函數。讓我們給他們的名字!

var form = document.querySelector('form') 
form.onsubmit = function formSubmit(submitEvent) { 
    var name = document.querySelector('input').value 
    request({ 
    uri: "http://example.com/upload", 
    body: name, 
    method: "POST" 
    }, function postResponse(err, response, body) { 
    var statusMessage = document.querySelector('.status') 
    if (err) return statusMessage.value = err 
    statusMessage.value = body 
    }) 
} 

正如你所看到的命名功能是超級簡單,做一些好東西給你的代碼:

  • 使代碼更易於閱讀
  • 當異常發生,你會得到引用的實際功能蹤跡名稱,而不是「匿名」
  • 可以讓你保持你的代碼淺,或沒有深度嵌套,這使我的下一個點:

保持代碼的淺

建築上的最後一個例子,讓我們走遠一點,擺脫,在代碼是怎麼回事三重級別嵌套:

function formSubmit(submitEvent) { 
    var name = document.querySelector('input').value 
    request({ 
    uri: "http://example.com/upload", 
    body: name, 
    method: "POST" 
    }, postResponse) 
} 

function postResponse(err, response, body) { 
    var statusMessage = document.querySelector('.status') 
    if (err) return statusMessage.value = err 
    statusMessage.value = body 
} 

document.querySelector('form').onsubmit = formSubmit 

這樣的代碼是那麼可怕查看並更容易編輯,稍後重構和破解。

Modularize!

這是最重要的部分:任何人都可以創建模塊(AKA庫)。引用(node.js項目的)Isaac Schlueter的話:「編寫一個小模塊,每個模塊都做一件事,然後將它們組裝成其他模塊,做更大的事情。如果你不去那裏,你不能進入回調地獄「。

讓我們從上面取出樣板代碼,並將其分成幾個文件,將其轉換爲模塊。由於我在瀏覽器和服務器上都編寫JavaScript,因此我將展示一種可以同時運行但仍然很好且簡單的方法。

這裏是一個名爲formuploader.js新文件,其中包含從我們的兩個函數之前:

function formSubmit(submitEvent) { 
    var name = document.querySelector('input').value 
    request({ 
    uri: "http://example.com/upload", 
    body: name, 
    method: "POST" 
    }, postResponse) 
} 

function postResponse(err, response, body) { 
    var statusMessage = document.querySelector('.status') 
    if (err) return statusMessage.value = err 
    statusMessage.value = body 
} 

exports.submit = formSubmit 
+0

優秀的參考資料爲http://callbackhell.com – abernier 2013-08-28 13:36:58

相關問題