減少陣列連結承諾

此設計模式對於從元素列表生成一系列非同步操作非常有用。

有兩種變體:

  • 然後減少,只要連鎖經歷成功,就會建立一個持續的鏈條。
  • 捕獲減少,只要鏈條出現錯誤,就會建立一個持續的鏈條。

****然後減少

這種模式的變體構建了一個 .then() 鏈,可能用於連結動畫或製作一系列依賴的 HTTP 請求。

[1, 3, 5, 7, 9].reduce((seq, n) => {
    return seq.then(() => {
        console.log(n);
        return new Promise(res => setTimeout(res, 1000));
    });
}, Promise.resolve()).then(
    () => console.log('done'),
    (e) => console.log(e)
);
// will log 1, 3, 5, 7, 9, 'done' in 1s intervals

說明:

  1. 我們在源陣列上呼叫 .reduce() ,並提供 Promise.resolve() 作為初始值。
  2. 減少的每個元素都會將 .then() 新增到初始值。
  3. reduce() 的產品將是 Promise.resolve()。然後(…)。然後(…)。
  4. 我們在 reduce 之後手動附加 .then(successHandler, errorHandler) ,以便在前面的所有步驟都已解決後執行 successHandler。如果任何步驟失敗,則 errorHandler 將執行。

注意:then 減少是 Promise.all() 的順序對應。

****捕獲減少

這種模式的變體構建了一個 .catch() 鏈,可用於為一些映象資源順序探測一組 Web 伺服器,直到找到工作伺服器。

var working_resource = 5; // one of the values from the source array
[1, 3, 5, 7, 9].reduce((seq, n) => {
    return seq.catch(() => {
        console.log(n);
        if(n === working_resource) { // 5 is working
            return new Promise((resolve, reject) => setTimeout(() => resolve(n), 1000));
        } else { // all other values are not working
            return new Promise((resolve, reject) => setTimeout(reject, 1000));
        }
    });
}, Promise.reject()).then(
    (n) => console.log('success at: ' + n),
    () => console.log('total failure')
);
// will log 1, 3, 5, 'success at 5' at 1s intervals

說明:

  1. 我們在源陣列上呼叫 .reduce() ,並提供 Promise.reject() 作為初始值。
  2. 每個元素減少將一個新增 .catch() 到初始值。
  3. reduce() 的產品將是 Promise.reject().catch(…).catch(...)
  4. 我們在 reduce 之後手動附加 .then(successHandler, errorHandler) ,以便在前面的任何步驟解決後執行 successHandler。如果所有步驟都失敗了,那麼 errorHandler 將會執行。

注意:catch 減少是 Promise.any() 的順序對應(在 bluebird.js 中實現,但目前不在本機 ECMAScript 中)。