Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ES7 async/await conceptual issue

I am migrating an existing program to use async/await (via Babel's bluebirdCoroutines) in order to learn this style. I have been looking at this tutorial.

I am a bit troubled by the following behavior. This snippet works as expected:

let parts = [];
let urlsP = urls.map((url, index) => { 
    return dlPart(url, index, tempDir); 
});
for (let urlP of urlsP) { // Parallel (yay!)
    parts.push(await urlP);
}
for (let part of parts) { // Sequential
    await appendFile(leFile, part);
}

Re-written as follows, it still works but the fist operation is not parallel any more (it takes much longer to finish)!

let index = 0;
let parts = [];
for (let url of urls) { // NOT Parallel any more!!!
    index++;
    parts.push(await dlPart(url, index, tempDir));
}
for (let part of parts) {
    await appendFile(leFile, part);
}

This is the implementation of dlPart()

function dlPart(url, num, dir) {
    var cmd = 'wget --quiet "' + url + '" -O ' + dir + "/" + num;
    return exec(cmd).then(() => {
        return dir + '/' + num;
    });
}

What am I missing?

like image 251
rollingBalls Avatar asked Jun 06 '15 00:06

rollingBalls


People also ask

What is async + await in ES7?

ES7’s Async + Await allows the developer to write more concise asynchronous code. It is just a piece of syntactical sugar for a developer’s JavaScript. An added bit of coding utility if you will. When implemented correctly, it can do the following: Essentially, async + await describes the use of a JavaScript Promise in a neat, more refined way.

What is async await in Node JS?

Node.js Async Await in ES7. One of the most exciting features coming to JavaScript (and therefore Node.js) is the async/await syntax being introduced in ES7. Although it's basically just syntactic sugar on top of Promises, these two keywords alone should make writing asynchronous code in Node much more bearable.

What are some examples of async/await syntax?

/// // Example of async/await syntax no. 1: Standart function async function someFunction () { await. } /// // Example of async/await syntax no. 2: Arrow function const someFunction = async () => { await. } /// // Example of async/await syntax no.

What are the benefits of async + await?

When the response is ready, the code will stop what its doing and revert back to the code that was intended to run once the request was finished. Once the basic concept of these two types of actions is understood, the benefits of Async + Await becomes more clear.


2 Answers

The reason that it is no longer running in parallel is because of the timing of when you are creating your promises in the two examples. This is described above comment more clearly.

In your first example you start all the Promises which begin to execute their functions. Then in this loop:

for (let urlP of urlsP) { // Parallel (yay!)
    parts.push(await urlP);
}

You wait for the first promise to be done, and then the second promise to be done, etc. But the whole time you are waiting for the first promise to be done ALL the other promises are still executing. Hence they run in "parallel".

In your second example, you both START and AWAIT the promises inside the loop instead of starting them all before the loop. So in this code:

for (let url of urls) { // NOT Parallel any more!!!
    index++;
    parts.push(await dlPart(url, index, tempDir));
}

The parts.push line does the following in order:

  1. Runs dlPart() which returns a promise and starts downloading the part
  2. Waits for the promise to resolve
  3. Pushes the resolved value into parts.

All the other promises have not been started and are not running "in parallel" they only get started when it's their turn in the loop. This means they get called one at a time, and only start the next one executing once the previous one is done and that is why they run iteratively.

Note: .map is not asynchronous if it were then your first example wouldn't work with large lists because the for of loop would start before all the promises were added to your urlsP array.

like image 108
Sam Avatar answered Nov 09 '22 12:11

Sam


The .map function is asynchronous so the rest of your code doesn't have to wait on it, it will finish when ready. Then you replaced it with a for loop that holds everything back while it completes.

like image 35
Datsik Avatar answered Nov 09 '22 11:11

Datsik