要验证这工作,我会成为一个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