2016-01-04 58 views
0

所以在這一點上,承諾似乎比回調更像「最佳實踐」,但許多現有的庫仍然使用回調。在承諾中包裝現有API的回調以避免「回調地獄」有什麼好處?

所以考慮到已經實現了這樣的回調格局庫:

library.connect(function(err) { 
    library.someQuery({}).exec(function(err, result) { 
    // some code 
    library.someQuery(result).exec(function(err2, result2) { 
     // some code 
    }) 
    }) 
}) 

有益處的諾言包裝這些回調,以避免嵌套?

new Promise((resolve, reject) => { 
    library.connect(function(err) { 
    if (err) reject(err) 
    else resolve() 
    } 
}).then(() => { 
    return new Promise((resolve, reject) => { 
    library.someQuery({}).exec((err, result) => { 
     if (err) reject(err) 
     else resolve(result) 
    } 
    }) 
}).then((result) => { 
    return new Promise((resolve, reject) => { 
    library.someQuery(result).exec(function(err2, result2) { 
     if (err) reject(err2) 
     else resolve(result2) 
    } 
}).then((result) => { 
    // some code 
}).catch((err) => // handle error) 

沒有嵌套它更好,但它更詳細。另外我不確定這會帶來多少額外的好處。也許更好的錯誤處理?

+3

在你的第一個片段中,你有多個位置來處理錯誤,而有了promise的你只有一個。 – andlrc

+0

@ dev-null是的我認爲這將是一個可能的答案。還有其他好處嗎?或者,也許可以減少冗長? – m0meni

+0

你可以創建helper函數'callbackToPromiseCallbacks(resolve,reject){return(err,res)=> err?拒絕(err):解析(res);}'以減少樣板代碼。 – Ginden

回答

1

這主要是意見,但:

  • 如果您不止一次這樣做,可能值得爲圖書館編寫一個基於Promise的API:

    import library from 'library'; 
    
    export default { 
        connect() { 
         return new Promise((resolve, reject) => { 
          library.connect(function(err) { 
          if (err) reject(err) 
          else resolve() 
          } 
         } 
        } 
        // etc 
    } 
    
  • 回調地獄/嵌套是一個實現問題,不是回調的基本問題,並且通常可以通過分解函數而不是嵌套來改善。像async這樣的庫使得回調與Promises一樣清晰易讀,或者更爲重要。

  • 承諾的一個優點(?)是,您可以使用async/await語法(假設Babel transpiling)。在實踐中,我發現這個語法很棘手,但有些人真的喜歡它。

2

在你的第一個片段中,你有多個地方來處理錯誤,而有了承諾你只有一個。

我認爲你提出了一些很好的觀察結果,還會增加使用承諾的性能方面的輕微開銷。但是,如果您可以重複使用重複代碼,那麼您可以使用它們更容易調試的代碼。

你也可以做一個小的功能抽象掉的承諾,但請記住,這將增加多一點的開銷:

// Non tested code, but hopes it shows a point 
function make_promisable(context, method) { 
    return new Promise((resolve, reject) => { 
    context[method]((err, result) => { 
     if (err) reject(err); 
     else resolve(result); 
    }); 
    }); 
}; 
// Note: The below actually seems to hide the logic in the code, 
// is this any good, or harder to read/debug? 
make_promisable(library, 'connect').then(() => { 
    return make_promisable(library.someQuery({}), 'exec'); 
}).then((result) => { 
    return make_promisable(library.someQuery(result), 'exec'); 
}).then((result) => { 
    // some code 
}).catch((err) => // handle error) 
相關問題