承诺和并发的递归
Recursion with promises and concurrency
请耐心等待,因为这需要一些设置。
为了问题/讨论的目的,考虑一下这个琐碎的价值观树。
const valuetree = [{
item: 1,
value: 100,
},
{
item: 2,
value: [{
item: 3,
value: [{
item: 4,
value: 200
},
{
item: 5,
value: 200
},
{
item: 6,
value: 200
},
]
}]
},
];
现在,如果我们想编写一个递归函数来将所有值相加,那么这本身就很简单了。像这样:
function sumTree(leaf) {
let total = 0;
if (Array.isArray(leaf)) {
leaf.forEach(subLeaf => {
total += sumTree(subLeaf);
});
} else {
if (Array.isArray(leaf.value)) {
total += sumTree(leaf.value);
} else {
total += Number(leaf.value);
}
}
return total;
}
现在假设我们想使用 promises 来实现同样的事情?
这就是我最终得到的...
async function sumTreeAsync(leaf) {
let promises = [];
if (Array.isArray(leaf)) {
leaf.forEach(async subLeaf => {
promises.push(sumTreeAsync(subLeaf));
});
} else {
if (Array.isArray(leaf.value)) {
promises.push(sumTreeAsync(leaf.value));
} else {
promises.push(leaf.value);
}
}
return promises;
}
那么 returned 看起来像这样
[ Promise { [ 100 ] }, Promise { [ [Promise] ] } ]
这是有道理的,一个包含 2 个顶级项目的数组,一个字面值的承诺,以及一个 return 嵌套承诺数组的承诺。
所以现在像 Promise.all 这样的函数只处理承诺的平面数组,我将不得不递归嵌套的承诺以达到相同的结果。所以现在我必须递归这棵树两次,它闻起来很糟糕。
所以也许我需要 return 解决 subleaf 是数组的 2 个案例中的承诺?
是否值得这样做,或者递归应该是同步的吗?
你离得不远了。如果您将 return 更改为进行 Promise .all
调用,并且将 .then (sum)
更改为一个明显的 sum
函数,这将起作用:
const sum = (ns) => ns .reduce ((a, b) => a + b, 0)
async function sumTreeAsync(leaf) {
let promises = [];
if (Array.isArray(leaf)) {
leaf.forEach(async subLeaf => {
promises.push(sumTreeAsync(subLeaf));
});
} else {
if (Array.isArray(leaf.value)) {
promises.push(sumTreeAsync(leaf.value));
} else {
promises.push(leaf.value);
}
}
return Promise.all(promises).then(sum);
}
const valuetree = [{item: 1, value: 100}, {item: 2, value: [{item: 3, value: [{item: 4, value: 200}, {item: 5, value: 200}, {item: 6, value: 200}]}]}];
sumTreeAsync (valuetree)
.then (console .log)
但我肯定会以不同的方式编写这段代码:
const sum = (ns) => ns .reduce ((a, b) => a + b, 0)
const sumTreeAsync = async (leaf) =>
Promise .all (Array .isArray (leaf)
? leaf.map (sumTreeAsync)
: Array .isArray (leaf .value)
? [sumTreeAsync (leaf .value)]
: [leaf .value]
) .then (sum)
const valuetree = [{item: 1, value: 100}, {item: 2, value: [{item: 3, value: [{item: 4, value: 200}, {item: 5, value: 200}, {item: 6, value: 200}]}]}];
sumTreeAsync (valuetree)
.then (console .log)
不止于此。我可能根本不会写这段代码。 JS 总体上还是一门单线程语言。所以你在这种方法中根本没有并发计算。如果您不是简单地求和,而是将事情交给不同的工人来处理,那么这可能是有道理的。实际上,这感觉像是一个不必要的并发症。
请耐心等待,因为这需要一些设置。
为了问题/讨论的目的,考虑一下这个琐碎的价值观树。
const valuetree = [{
item: 1,
value: 100,
},
{
item: 2,
value: [{
item: 3,
value: [{
item: 4,
value: 200
},
{
item: 5,
value: 200
},
{
item: 6,
value: 200
},
]
}]
},
];
现在,如果我们想编写一个递归函数来将所有值相加,那么这本身就很简单了。像这样:
function sumTree(leaf) {
let total = 0;
if (Array.isArray(leaf)) {
leaf.forEach(subLeaf => {
total += sumTree(subLeaf);
});
} else {
if (Array.isArray(leaf.value)) {
total += sumTree(leaf.value);
} else {
total += Number(leaf.value);
}
}
return total;
}
现在假设我们想使用 promises 来实现同样的事情?
这就是我最终得到的...
async function sumTreeAsync(leaf) {
let promises = [];
if (Array.isArray(leaf)) {
leaf.forEach(async subLeaf => {
promises.push(sumTreeAsync(subLeaf));
});
} else {
if (Array.isArray(leaf.value)) {
promises.push(sumTreeAsync(leaf.value));
} else {
promises.push(leaf.value);
}
}
return promises;
}
那么 returned 看起来像这样
[ Promise { [ 100 ] }, Promise { [ [Promise] ] } ]
这是有道理的,一个包含 2 个顶级项目的数组,一个字面值的承诺,以及一个 return 嵌套承诺数组的承诺。
所以现在像 Promise.all 这样的函数只处理承诺的平面数组,我将不得不递归嵌套的承诺以达到相同的结果。所以现在我必须递归这棵树两次,它闻起来很糟糕。
所以也许我需要 return 解决 subleaf 是数组的 2 个案例中的承诺?
是否值得这样做,或者递归应该是同步的吗?
你离得不远了。如果您将 return 更改为进行 Promise .all
调用,并且将 .then (sum)
更改为一个明显的 sum
函数,这将起作用:
const sum = (ns) => ns .reduce ((a, b) => a + b, 0)
async function sumTreeAsync(leaf) {
let promises = [];
if (Array.isArray(leaf)) {
leaf.forEach(async subLeaf => {
promises.push(sumTreeAsync(subLeaf));
});
} else {
if (Array.isArray(leaf.value)) {
promises.push(sumTreeAsync(leaf.value));
} else {
promises.push(leaf.value);
}
}
return Promise.all(promises).then(sum);
}
const valuetree = [{item: 1, value: 100}, {item: 2, value: [{item: 3, value: [{item: 4, value: 200}, {item: 5, value: 200}, {item: 6, value: 200}]}]}];
sumTreeAsync (valuetree)
.then (console .log)
但我肯定会以不同的方式编写这段代码:
const sum = (ns) => ns .reduce ((a, b) => a + b, 0)
const sumTreeAsync = async (leaf) =>
Promise .all (Array .isArray (leaf)
? leaf.map (sumTreeAsync)
: Array .isArray (leaf .value)
? [sumTreeAsync (leaf .value)]
: [leaf .value]
) .then (sum)
const valuetree = [{item: 1, value: 100}, {item: 2, value: [{item: 3, value: [{item: 4, value: 200}, {item: 5, value: 200}, {item: 6, value: 200}]}]}];
sumTreeAsync (valuetree)
.then (console .log)
不止于此。我可能根本不会写这段代码。 JS 总体上还是一门单线程语言。所以你在这种方法中根本没有并发计算。如果您不是简单地求和,而是将事情交给不同的工人来处理,那么这可能是有道理的。实际上,这感觉像是一个不必要的并发症。