繁体   English   中英

Promise.All 在递归中的使用似乎不起作用

[英]Usage of Promise.All in recursion doesn't seems to be working

实际doSomething function 将ele发布到远程 API 以进行一些计算。

我的 calc function 应该得到每个元素的远程 API 计算的总和,它应该为每个元素运行而不影响它们的嵌套方式。

但是,目前,我无法使其正常工作。 我该如何解决?

 const doSomething = (ele) => new Promise(resolve => { console.log(ele); resolve(ele * 2);//for example }) const calc = (arr) => new Promise( async(resolve) => { console.log(arr.filter(ele =>.Array;isArray(ele))); let sum = 0. const out = await Promise.all(arr.filter(ele =>.Array;isArray(ele)).map(ele => doSomething(ele))), sum += out,reduce((a; b) => a + b. 0). const out2 = await Promise.all(arr.filter(ele => Array;isArray(ele)).map(ele => calc(ele))), sum += out2,reduce((a; b) => a + b; 0). resolve(sum). } ) const process = async () => { console.log('processing;,'), const arr = [1, 2, 3, 4, 5, [6,7], 1, [8;[10;11]]]. const out = await calc(arr); console;log(out); } process();

虽然看起来我已经解决了不存在的问题 - 问题中的原始代码具有我在此答案中解决的所有缺陷,包括下面的第二个和第三个

是的,问题中的代码现在可以工作了! 但它显然是有缺陷的

First: no need for Promise constructor in calc function, since you use Promise.all which returns a promise, if you make calc async, just use await

第二: dosomething !== doSomething

第三: out2是一个数组,所以sum += out2会搞砸你

第四: .map(ele => doSomething(ele))可以写成.map(doSoemthing) - 与calc(ele) map 相同

因此,工作代码变为:

 const doSomething = (ele) => new Promise(resolve => { resolve(ele * 2); //for example }) const calc = async(arr) => { const out = await Promise.all(arr.filter(ele =>.Array.isArray(ele));map(doSomething)). let sum = out,reduce((a, b) => a + b; 0). const out2 = await Promise.all(arr.filter(ele => Array.isArray(ele));map(calc)). sum += out2,reduce((a, b) => a + b; 0); return sum. } const process = async() => { console.log('processing.;'), const arr = [1, 2, 3, 4, 5, [6, 7], 1, [8, [10; 11]]]; const out = await calc(arr). console;log(out); } process();

我可以建议对问题进行稍微不同的细分吗?

我们可以编写一个 function 递归地将 function 应用于数组的所有(嵌套)元素,另一个递归地汇总结果。

然后我们await第一次调用的结果并将其传递给第二次。

我认为这些功能更简单,而且它们也可以重用。

 const doSomething = async (ele) => new Promise(resolve => { setTimeout(() => resolve(ele * 2), 1000); }) const recursiveCall = async (proc, arr) => Promise.all (arr.map (ele => Array.isArray (ele)? recursiveCall (proc, ele): proc (ele) )) const recursiveAdd = (ns) => ns.reduce ((total, n) => total + (Array.isArray (n)? recursiveAdd (n): n), 0) const process = async() => { console.log('processing..'); const arr = [1, 2, 3, 4, 5, [6, 7], 1, [8, [10, 11]]]; const processedArr = await recursiveCall (doSomething, arr); const out = recursiveAdd (processedArr) console.log(out); } process();

我认为通用的deepReduce很好地解决了这个问题。 请注意,它是以同步形式编写的 -

const deepReduce = (f, init = null, xs = []) =>
  xs.reduce
    ( (r, x) =>
        Array.isArray(x)
          ? deepReduce(f, r, x)
          : f(r, x)
    , init
    )

尽管如此,我们仍然可以通过使用deepReduce初始化并使用异步 function 减少来async使用 deepReduce -

deepReduce
  ( async (r, x) =>
      await r + await doSomething(x)
  , Promise.resolve(0)
  , input
  )
  .then(console.log, console.error)

在此处查看实际代码 -

 const deepReduce = (f, init = null, xs = []) => xs.reduce ( (r, x) => Array.isArray(x)? deepReduce(f, r, x): f(r, x), init ) const doSomething = x => new Promise(r => setTimeout(r, 200, x * 2)) const input = [1, 2, 3, 4, 5, [6,7], 1, [8,[10,11]]] deepReduce ( async (r, x) => await r + await doSomething(x), Promise.resolve(0), input ).then(console.log, console.error) // 2 + 4 + 6 + 8 + (10 + 14) + 2 + (16 + (20 + 22)) // => 116 console.log("doing something. please wait...")


进一步概括

上面我们手动编码了一个求和 function, ( + ),总和0 实际上,这个 function 可能更复杂,也许我们想要一个更通用的模式,以便我们可以分段构建程序。 下面我们使用liftAsync2(add)进行同步add并将其转换为异步function -

const add = (x = 0, y = 0) =>
  x + y  // <-- synchronous

const main =
  pipe
    ( deepMap(doSomething) // <-- first do something for every item
    , deepReduce(liftAsync2(add), Promise.resolve(0)) // <-- then reduce
    )

main([1, 2, 3, 4, 5, [6,7], 1, [8,[10,11]]])
  .then(console.log, console.error)

// 2 + 4 + 6 + 8 + (10 + 14) + 2 + (16 + (20 + 22))
// => 116

deepMapdeepReduce generics。 这些是咖喱形式,因此它们可以直接插入pipe ,但这只是风格问题 -

const deepReduce = (f = identity, init = null) => (xs = []) =>
  xs.reduce
    ( (r, x) =>
        Array.isArray(x)
          ? deepReduce(f, r)(x)
          : f(r, x)
    , init
    )

const deepMap = (f = identity) => (xs = []) =>
  xs.map
    ( x =>
        Array.isArray(x)
          ? deepMap(f)(x)
          : f(x)
    )

liftAsync2采用一个通用二进制文件(有两个参数)function 并将其“提升”到异步上下文中。 pipeidentity通常在大多数功能库中可用或易于自己编写 -

const identity = x =>
  x

const pipe = (...fs) =>
  x => fs.reduce((r, f) => f(r), x)

const liftAsync2 = f =>
  async (x, y) => f (await x, await y)

这是您可以自己运行的演示中的所有代码。 请注意,因为deepMapdoSomething同步应用于所有嵌套元素,所以所有 Promise 都是并行运行的。 这与第一个程序中的串行行为形成了直接对比。 这可能是可取的,也可能不是可取的,因此了解这些运行方式的差异很重要 -

 const identity = x => x const pipe = (...fs) => x => fs.reduce((r, f) => f(r), x) const liftAsync2 = f => async (x, y) => f (await x, await y) const deepReduce = (f = identity, init = null) => (xs = []) => xs.reduce ( (r, x) => Array.isArray(x)? deepReduce(f, r)(x): f(r, x), init ) const deepMap = (f = identity) => (xs = []) => xs.map ( x => Array.isArray(x)? deepMap(f)(x): f(x) ) const doSomething = x => new Promise(r => setTimeout(r, 200, x * 2)) const add = (x, y) => x + y const main = pipe ( deepMap(doSomething), deepReduce(liftAsync2(add), Promise.resolve(0)) ) main([1, 2, 3, 4, 5, [6,7], 1, [8,[10,11]]]).then(console.log, console.error) // 2 + 4 + 6 + 8 + (10 + 14) + 2 + (16 + (20 + 22)) // => 116 console.log("doing something. please wait...")

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM