0

The program description

Create 3 functions:
FuncA – will receive a string and returns it’s length
FuncB – will receive an array of strings and returns their total lengths (using
funcA) after 2 seconds.
FuncC - will receive an array of arrays of strings and returns their total lengths
(using FuncB)

My solution is

    function funcA(s)
    {
        return s.length
    }

    function funcB(arr)
    {
        return new Promise(resolve =>
            {
                setTimeout(() =>
                {
                    let total = 0;
                    arr.forEach(element => {
                        total += funcA(element)
                    });
                    resolve(total)
                },2000)
            })
    }

    function funcC(arr)
    {      
            return new Promise(resolve =>
                {
                    let isFirst = true
                    //a <=> total
                    let total = arr.reduce(async (a,b) =>
                    {
                        if(isFirst) {
                           isFirst = false
                           return (await funcB(a) + await funcB(b))
                        }
                        else {//a <=> total
                            return (a + await funcB(b))
                        }
                    })
                    resolve(total)
                }) 
    }

The running is:
funcC([["aa","bbb","tyui"],["ccc"],["dfghj","aedtfr"]]).then(x => console.log(x))

The result is: [object Promise]11

What is the problem?

Alex B
  • 3
  • 4

2 Answers2

1

This is really convoluted.

  • Don't put business logic in the setTimeout callback. Only resolve the promise, then do the work in a promise then callback or after an await.
  • Always pass an initial value to reduce! This will make it work with empty arrays, and it will obviate the need for that really weird isFirst logic.
  • total already is a promise. Don't unnecessarily wrap it in a new Promise!

These suggestions will lead to

function funcA(s) { return s.length }

function funcB(arr) {
    return new Promise(resolve => {
        setTimeout(resolve, 2000);
    }).then(() => {
        let total = 0;
        arr.forEach(element => {
            total += funcA(element)
        });
        return total;
    });
}

function funcC(arr) {      
    return arr.reduce(async (a,b) => {
        return await a + await funcB(b)
    }, Promise.resolve(0))
}

However, reduce is not really suited for asynchronous work. You should rather use the looping approach in funcC, and use reduce in funcB where it fits much better:

async function funcB(arr) {
    await new Promise(resolve => {
        setTimeout(resolve, 2000);
    });
    return arr.reduce((total, element) => total + funcA(element), 0);
}

async function funcC(arr) {
    let total = 0;
    for (const b of arr) {
        total += funcB(b);
    }
    return total;
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
0

[fixed the answer]

you shall do await a instead of a everywhere

function funcC(arr)
{      
    return new Promise(resolve =>
        {
            let isFirst = true
            //a <=> total
            let total = arr.reduce(async (a,b) =>
            {
                if(isFirst) {
                    isFirst = false
                    return (await funcB(await a) + await funcB(b))
                }
                else {//a <=> total
                    return (await a + await funcB(b))
                }
            })
            resolve(total)
        }) 
}
crystalbit
  • 664
  • 2
  • 9
  • 19
  • ok, found problem, you shall do `await a` instead of `a` everywhere – crystalbit May 03 '20 at 20:19
  • hm, I evaluated it and got a result (added only two awaits) – crystalbit May 03 '20 at 20:27
  • Thank you very much. I didn't know what can be the problem. How you explain your change to 'await a'? How can I vote for your right answer? – Alex B May 03 '20 at 22:15
  • async functions always return a promise, this one in reduce too. accumulator `a` is still the result of previous iteration, but it is a promise due to `async` in reduce. don't know how to vote for the right answer :) – crystalbit May 03 '20 at 22:22
  • 1
    I thought in the same direction that previous iteration goes to 'a'. Your explanation is full. Thank you very much again. I tapped V under the top of your answer – Alex B May 03 '20 at 22:26