2016-09-07 173 views
8

我正在嘗試使用Promises創建遞歸函數,但似乎無法完成正確的操作。我有工作代碼沒有使用承諾,但它使用計數器和全局變量等,並不覺得很正確,所以我正在嘗試重寫,並創建一個模塊重用。Javascript遞歸承諾

本質上,該功能應該是從Active Directory獲取用戶,然後遞歸查找任何直接報告及其直接報告等。

我已經有很多的功能版本的發揮,這是當前一個:

function loadReports(personEmail, list) { 
    return new Promise((resolve, reject) => { 
     getAccessTokenPromise() 
      .then(access_token => { 
       list.push(personEmail); 
       return makeRequest(personEmail, access_token); 
      }).then(result => { 
       if (result.value.length > 0) { 
        Promise.all(result.value.map(person => { 
         loadReports(person.userPrincipalName, list); 
        })).then(resolve()); 
       } else { 
        resolve(); 
       } 
      }) 
      .catch(e => reject(e)); 
    }); 
} 

getAccessTokenPromise函數執行訪問令牌的請求,並返回一個承諾。 makeRequest函數再次爲用戶及其報告提供https請求,並返回一個結果作爲Promise的json對象。

任何想法大大收到。非常感謝。 D.

+1

「但它使用計數器和全局變量等」---現在你看到不純的函數和自由變量是多麼邪惡。首先重新實現它,以便它不依賴於來自外部範圍的變量,然後將其提供。 – zerkms

回答

6

爲了使遞歸與承諾一起工作,您通常希望將所有遞歸承諾鏈接到它們的調用者。要做到這一點,您必須從您的.then()處理程序返回任何承諾,以便它們鏈接到原件。這也傾向於消除用包含問題的手動創建的承諾來包裝現有承諾的promise anti-pattern。下面是這樣做的一種方式:

function loadReports(personEmail, list) { 
    return getAccessTokenPromise().then(access_token => { 
     list.push(personEmail); 
     return makeRequest(personEmail, access_token); 
    }).then(result => { 
     if (result.value.length > 0) { 
      return Promise.all(result.value.map(person => { 
       return loadReports(person.userPrincipalName, list); 
      })); 
     } 
    }); 
} 

所做的更改:

  1. getAccessTokenPromise之前添加return(),所以我們返回了最初的承諾。這也讓我們消除了new Promise()以及所有涉及反模式的手動拒絕和解決方案。

  2. 在遞歸之前加上returnloadReports()。必須這樣做才能允許.map()收集該承諾,然後將其傳遞到Promise.all()

  3. Promise.all()之前加return所以它被鏈接到最初的承諾鏈。


你必須確保你永遠無法得到數據在數據庫中任何類型的圓度(以創建報表循環列表數據庫錯誤)。向B報告,B向C報告,C向A報告,因爲如果你確實有這種情況,那麼這段代碼將永遠持續下去,永遠不會完成(可能最終耗盡一些系統資源)。

如果這是我的代碼,那麼我可以創建一個所有在數據庫中訪問過的人的集合,並拒絕對我們以前已經訪問的任何人調用loadReports()。這將使它免於循環。如果您看到該情況,您可能還需要log(),因爲它可能是數據庫錯誤/損壞。

+0

謝謝。是的,這是更好,更整齊。謝謝你的解釋,非常有用。通過將最後一個'.then(resolve());'改成'.then(results => {resolve()}),我得到了一個可以工作的解決方案。 ',但我更喜歡你的解決方案。非常感謝。 – Darren

+0

另外,最後一點感謝,在嘗試之前沒有超過「代碼/更改」部分。這很有趣,因爲我最終想要一個Set,因爲我將結果與另一個系統上的成員進行比較,所以我可能會介紹這一點。信息來自http://graph.microsoft.io,所以希望可靠;)。 – Darren

+0

@Darren,你應該考慮只是'。然後(解決)'。 :) –