0

I have two promises in chain, like this:

router.get('/:address', function (req, res, next) {

    let prodotti = [];

    istanza.methods.getProductByOwner("xxxxx").call().then(
        ids => {
            for (let id of ids) {
                istanza.methods.prodotti(id).call().then(
                    prod => {
                        prodotti.push(prod);
                    },
                    error => console.dir(error)
                )
            }
        },
        err => console.log("ritiro KO " + err)
    );

    res.render('profilo', {address: req.params.address, prodotti: prodotti});

});

I want to have prodotti filled, when the for is finished.

I try this way:

router.get('/:address', function (req, res, next) {
    let prodotti = [];

    istanza.methods.getProductByOwner("xxxx").call().then(
        ids => {
            f(ids)
        },
        err => console.log("ritiro KO " + err)
    );
    res.render('profilo', {address: req.params.address, prodotti: prodotti});

});

and then

async function f(ids) {
    let prodotti = [];
    let promises = []

    promises.push(new Promise((resolve, reject) => {
        for (let id of ids) {
            promises.push(istanza.methods.prodotti(id).call().then(
                prod => {
                    prodotti.push(prod);
                    //resolve when for is finished
                    if(id == (ids.length)-1){
                        resolve(prodotti)
                    }
                    id++;
                },
                error => console.dir(error)
            ));
        }

    }));

    let result = await Promise.all(promises);
    console.log("await " + result);
}

but my result is:

,,,[object Object],[object Object],[object Object]

I Want get result only when for is finished, and I don't like to use condition like this:

if(id == (ids.length)-1)
monkeyUser
  • 4,301
  • 7
  • 46
  • 95

2 Answers2

1

seems you need to handle your promise from the initial api renderer correctly:

router.get('/:address', async (req, res, next) => {   
    let ids = await istanza.methods.getProductByOwner("xxxx").call().catch(err => 
        console.log("ritiro KO " + err)
    );
    let prodotti = await Promise.all(ids.map( async f ));
    res.render('profilo', {address: req.params.address, prodotti: prodotti});

});

your other function can then handle each id individually:

function f(id) {
    return istanza.methods.prodotti(id).call().catch(console.dir)
}

I assumed a few things, such as the .call() method returns a promise (from the syntax, it seems like it does). WARNING, this code is not tested!

NOTE: Updated w/ Bergi's comment

LostJon
  • 2,287
  • 11
  • 20
  • perfect ! can you explain please? – monkeyUser Nov 05 '18 at 19:23
  • 1
    glad it worked! so, `await` will essentially unwrap a promise; whereas `async` will wrap a return in a promise. when iterating `ids`, leveraging `Promise.all` in conjunction with `.map(async () => {}` will result in the .map return an array of promises for you already (nifty!!!) – LostJon Nov 05 '18 at 19:26
  • 2
    Better also avoid the `push` in the callback and just use `const prodotti = await Promise.all(ids.map(f))` – Bergi Nov 05 '18 at 20:28
  • @Bergi Can I omit ```id => f(id)``` , why? – monkeyUser Nov 05 '18 at 20:43
  • @monkeyUser you can't omit it, but you can shorten it to `f`. All you need to do is pass a function that returns the promise you want - how you do that doesn't matter. – Bergi Nov 05 '18 at 20:48
0

You have to iterate over each ids value and push the promise into array and then wait for all promises to be resolved. Once resolved you can get the response in result and push that into prodotti.

Try this

let promises = [];
async function f(ids) {

    for (let id of ids) {
       var promise = istanza.methods.prodotti(id).call().then(
                prod => {
                   return prod;
                },
                error => return error;
            );
        promises.push(promise);    
  }
    let prodotti = await Promise.all(promises);
    console.log("await " + prodotti);
}
front_end_dev
  • 1,998
  • 1
  • 9
  • 14
  • thanks for your answer, the result is ```await ,[object Object],,[object Object],,[object Object]``` – monkeyUser Nov 05 '18 at 19:04
  • `result.reduce(function(o,i){ o.push(i); return o; },[]);` makes no sense. Just `const prodotti = results;` (or even omit the temporary variable). – Bergi Nov 05 '18 at 20:29