Iteration in Async Land

Concurrent Iterations

Arijit Bhattacharya
Trying to Manipulate the DOM
2 min readJun 9, 2018

--

The concept of iteration intuitively seems to be synchronous — when the iteration completes we will have our results ready.

There are many native array methods which helps us iterate over an array.

Lets say we have an array of student details. Each student has a field which states their date of birth and now we want to calculate their age.

const ageOfStudents = studentDetails.map(function (student) {
return calculateAgeFromDOB(student.dob);
});

The ageOfStudents will be ready for us immediately.

calculateAgeFromDOB is a synchronous operation. So, we will calculate the age of each student strictly one after the other.

But what if the operation to be applied to each student does not resolve synchronously.

Lets say, we need yearly performance record for each student. And each yearly performance record of a student is a network request.

const studentPerformanceRecordsPromises = studentDetails
.map(({id}) => getPerformanceRecordOfStudent(id));

Each iteration will spawn a concurrent task. And these tasks will resolve in their own arbitrary order.

We have to wait for the performance records even after the iteration completes. This is the critical distinction between ordinary iteration and concurrent iteration.

If getPerformanceRecordOfStudent returns a Promise which resolves after a successful network request, studentPerformanceRecordsPromises will be an array of Promises.

We can use Promise.all to wait on an array of Promises.

Promise.all(studentPerformanceRecordsPromises)
.then(doSomethingWithPerformanceRecordsOfAllStudents)

Since we are contrasting synchronous and asynchronous iteration, it will be good to have an async counterpart of our Array.map.

We will like to use it like this

Promise
.map(studentDetails, getPerformanceRecordOfStudent)
.then(doSomethingWithPerformanceRecordsOfAllStudents)

And here is how a trivial definition of Promise.map will look like

if (!Promise.map) {
Promise.map = function(vals,cb) {
return Promise.all(
vals.map( function(val){
// we are expecting `cb` to return a promise
// even if it does not we are converting it in to
// a promise using `Promise.resolve`
return Promise.resolve(cb(val))
} )
);
};
}

This thought was spawned while I was reading YDKJS by @getify. Particularly this part aptly titled Concurrent Iterations. I was scratching my head for a little while.

So thought of sharing my resolved understanding. Maybe this will help somebody.

Thanks for reading.

I am a big fan of YDKJS. Highly recommend it!

Resolve your relationship with JavaScript. Sorry!

--

--

Arijit Bhattacharya
Trying to Manipulate the DOM

Self learner, JavaScript performer, Minimal design practitioner, Honest effort admirer. Frontend human @Freshdesk