要驗證這工作,我會成爲一個fake
數據集,以及fakeAsyncOperation
從數據集讀取數據異步。要密切建模您的數據,來自假數據集的每個查詢將返回一個帶有data
和pages
字段的響應。
let fake = new Map([
['root', {data: 'root', pages: ['a', 'b', 'c', 'd']}],
['a', {data: 'a', pages: ['a/a', 'a/a']}],
['a/a', {data: 'a/a', pages: []}],
['a/b', {data: 'a/b', pages: ['a/b/a']}],
['a/b/a', {data: 'a/b/a', pages: []}],
['b', {data: 'b', pages: ['b/a']}],
['b/a', {data: 'b/a', pages: ['b/a/a']}],
['b/a/a', {data: 'b/a/a', pages: ['b/a/a/a']}],
['b/a/a/a', {data: 'b/a/a/a', pages: []}],
['c', {data: 'c', pages: ['c/a', 'c/b', 'c/c', 'c/d']}],
['c/a', {data: 'c/a', pages: []}],
['c/b', {data: 'c/b', pages: []}],
['c/c', {data: 'c/c', pages: []}],
['c/d', {data: 'c/d', pages: []}],
['d', {data: 'd', pages: []}]
]);
let fakeAsyncOperation = (page) => {
return new Promise(resolve => {
setTimeout(resolve, 100, fake.get(page))
})
}
接下來我們有你的foo
函數。我已將doo
更名爲enqueue
,因爲它的工作方式類似於隊列。它有兩個參數:acc
用於跟蹤累計數據,xs
(已解組),它是隊列中的項目。
我已經使用了新的async/await
語法,這對於處理這個問題特別好。我們不必手動構建任何承諾或處理任何手動鏈接。
我做自由使用傳播語法的遞歸調用,因爲我的可讀性,但你可以很容易,如果你喜歡,更多的替換這些爲concat
電話acc.concat([data])
和xs.concat(pages)
。 - 這是函數式編程,所以只需選擇一個你喜歡的不可變操作並使用它。
最後,與其他使用Promise.all
的答案不同,這將處理系列中的每個頁面。如果一個頁面有50個子頁面,則Promise.all
會嘗試在並行中發出50個請求,這可能是不希望的。將程序從並行轉換爲串行不一定簡單,所以這就是提供這個答案的原因。
function foo (page) {
async function enqueue (acc, [x,...xs]) {
if (x === undefined)
return acc
else {
let {data, pages} = await fakeAsyncOperation(x)
return enqueue([...acc, data], [...xs, ...pages])
}
}
return enqueue([], [page])
}
foo('root').then(pages => console.log(pages))
輸出
[ 'root',
'a',
'b',
'c',
'd',
'a/a',
'a/a',
'b/a',
'c/a',
'c/b',
'c/c',
'c/d',
'b/a/a',
'b/a/a/a' ]
備註
我很高興,我的解決方案的foo
功能不是從原始的太遠了 - 我想你會明白, 。它們都使用內部輔助功能進行循環,並以類似的方式處理問題。 async/await
使代碼保持良好的平坦性和高度可讀性(imo)。總的來說,我認爲這是一個有點複雜的問題的絕佳解決方案。
哦,不要忘了循環引用。在我的數據集中沒有循環引用,但是如果頁面'a'
有pages: ['b']
和'b'
有pages: ['a']
,則可以預期無限遞歸。由於該答案能夠連續處理頁面,因此這將非常容易解決(通過檢查累積值acc
獲取現有頁面標識符)。當並行處理頁面時,這是非常棘手的(並且這個答案超出了範圍)。
你對「頁面」數據有什麼期望?你不會在'if(resp.pages)'塊中返回任何東西,並且在傳給'forEach'的函數中使用的返回不起任何作用 – Phil
當'resp.pages'爲真時,你不返回任何東西,這等於'返回undefined'。 – Leo