简体   繁体   English

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

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

Actual doSomething function posts ele to a remote API to do some calculations.实际doSomething function 将ele发布到远程 API 以进行一些计算。

My calc function supposed to get the summation of the remote API's calculation for each element, It should run for every element without affecting how nested they are located.我的 calc function 应该得到每个元素的远程 API 计算的总和,它应该为每个元素运行而不影响它们的嵌套方式。

However, Currently, I can't get this to work.但是,目前,我无法使其正常工作。 How do I fix this?我该如何解决?

 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();

While it may look like I've addressed issues that are non-existent - the original code in the question had ALL the flaws I address in this answer, including Second and Third below虽然看起来我已经解决了不存在的问题 - 问题中的原始代码具有我在此答案中解决的所有缺陷,包括下面的第二个和第三个

yes, the code in the question now works!是的,问题中的代码现在可以工作了! But it clearly was flawed但它显然是有缺陷的

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 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

Second: dosomething !== doSomething第二: dosomething !== doSomething

Third: out2 is an array, so sum += out2 is going to mess you up第三: out2是一个数组,所以sum += out2会搞砸你

Fourth: .map(ele => doSomething(ele)) can be written .map(doSoemthing) - and the same for the calc(ele) map第四: .map(ele => doSomething(ele))可以写成.map(doSoemthing) - 与calc(ele) map 相同

So, working code becomes:因此,工作代码变为:

 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();

Can I suggest a slightly different breakdown of the problem?我可以建议对问题进行稍微不同的细分吗?

We can write one function that recursively applies your function to all (nested) elements of your array, and another to recursively total the results.我们可以编写一个 function 递归地将 function 应用于数组的所有(嵌套)元素,另一个递归地汇总结果。

Then we await the result of the first call and pass it to the second.然后我们await第一次调用的结果并将其传递给第二次。

I think these functions are simpler, and they are also reusable.我认为这些功能更简单,而且它们也可以重用。

 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();

I think a generic deepReduce solves this problem well.我认为通用的deepReduce很好地解决了这个问题。 Notice it's written in synchronous form -请注意,它是以同步形式编写的 -

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

Still, we can use deepReduce asynchronously by initialising with a promise and reducing with an async function -尽管如此,我们仍然可以通过使用deepReduce初始化并使用异步 function 减少来async使用 deepReduce -

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

See the code in action here -在此处查看实际代码 -

 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...")


further generalisation进一步概括

Above we are hand-encoding a summing function, ( + ), with the empty sum 0 .上面我们手动编码了一个求和 function, ( + ),总和0 In reality, this function could be more complex and maybe we want a more general pattern so we can construct our program piecewise.实际上,这个 function 可能更复杂,也许我们想要一个更通用的模式,以便我们可以分段构建程序。 Below we take synchronous add and convert it to an asynchronous function using liftAsync2(add) -下面我们使用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

deepMap and deepReduce generics. deepMapdeepReduce generics。 These are in curried form so they can plug directly into pipe , but that is only a matter of style -这些是咖喱形式,因此它们可以直接插入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 takes a common binary (has two parameters) function and "lifts" it into the asynchronous context. liftAsync2采用一个通用二进制文件(有两个参数)function 并将其“提升”到异步上下文中。 pipe and identity are commonly available in most functional libs or easy to write yourself - 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)

Here's all of the code in a demo you can run yourself.这是您可以自己运行的演示中的所有代码。 Notice because deepMap synchronously applies doSomething to all nested elements, all promises are run in parallel.请注意,因为deepMapdoSomething同步应用于所有嵌套元素,所以所有 Promise 都是并行运行的。 This is in direct contrast to the serial behaviour in the first program.这与第一个程序中的串行行为形成了直接对比。 This may or may not be desirable so it's important to understand the difference in how these run -这可能是可取的,也可能不是可取的,因此了解这些运行方式的差异很重要 -

 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