DEV Community

Itachi Uchiha
Itachi Uchiha

Posted on

Then After forEach

Hi. I need a function to make sure forEach is completed in JavaScript.

Simply I created this function;

Object.defineProperty(Array.prototype, "asyncForEach", {
    enumerable: false,
    value: function(task){
        return new Promise((resolve, reject) => {
            this.forEach(function(item, index, array){
                task(item, index, array);
                if(Object.is(array.length - 1, index)){
                    resolve({ status: 'finished', count: array.length })
                }
            });        
        })
    }
});
Enter fullscreen mode Exit fullscreen mode

I use this function like below;


homePage.disabled = true

orders.asyncForEach(function (order) {
    api.sendOrder(order)
}).then(function (data) {
    homePage.disabled = false
})
Enter fullscreen mode Exit fullscreen mode

This function works as I expect.

So friends, do you know any other ways? Is this an optimized way to catch async operations are completed?

Top comments (5)

Collapse
 
matchojecky profile image
Mateusz • Edited
const orderPromises = orders.map(order => api.sendOrder(order));
Promise.all(orderPromisses).then(arrayOfResponses => {
    // do your stuff
})

You have over overengineered this and your solution wasn't really working as it should.

Collapse
 
forstermatth profile image
Matt Forster • Edited

Yes, This is definitely the solution! Node has native support for dealing with multiple async promises.

You could even remove the variable assignment (though JS is going to assign it to a temp anyways);


return Promise.all(orders.map(api.sendOrder))
  .then(allOrders => {
    ...
  });

Thats if sendOrder does not need its functional context. Semantically the same solution, though.

Collapse
 
anduser96 profile image
Andrei Gatej

I've come up with this solution:

(async () => {
    const fetch = (name, time) => new Promise(resolve => setTimeout(resolve, time, name))
    const orders = [fetch('order1', 500), fetch('order2', 700), fetch('order3', 1000), fetch('order4', 1200)];

    orders[Symbol.asyncIterator] = async function * () {
        yield * [...this];
    }

    for await (const resolvedOrder of orders) {
        console.log(resolvedOrder)
    }

    console.log('finished !')
    /*
    order1
    order2
    order3
    order4
    finished!
    */
})()

I wouldn't say your approach is not optimized, it looks fine to me. I have to mention that I'm not very experienced though, so I'm not sure my opinion is 100% accurate.

I hope this was helpful to you in some way.

Collapse
 
joelnet profile image
JavaScript Joel

With MojiScript I have created an async map, filter and reduce to make things like this cake.

import map from 'mojiscript/list/map'

const sleep = timeout => new Promise(resolve => setTimeout(resolve, timeout))

const array = [ 1, 2, 3 ]

const asyncTransform = async x => {
  await sleep(1000)
  return x * 2
}

map (asyncTransform) (array) //=> Promise ([ 2, 4, 6 ])

Check it out here: mojiscript.js.org/#/list-map

Also related: Why async code is so damn confusing (and a how to make it easy)

Collapse
 
kkouomeu profile image
Kevin Kouomeu
const customArrayProperty = (originArray: Array<any>) => {
  let offset: number = 0;
  Object.defineProperty(Array.prototype, "asyncForEach", {
    enumerable: false,
    configurable: true,
    value: function (task) {
      return new Promise((resolve, reject) => {
        this.forEach(function (item, index, array) {
          task(item, index, array);
          setTimeout(() => {
            console.log(index);
            if (Object.is(index, originArray.length - 1)) {
              resolve({ status: "finished", count: array.length });
            }
          }, 1000 + offset);
          offset += 1000;
        });
      });
    },
  });
};

Enter fullscreen mode Exit fullscreen mode