You can better see the differences between the code when its written in a slightly different way.
For all intents and purposes this is exactly what Sam has explained, but in a way that I find helps developers understand it in a way that they are more accustomed to.
ES7 Code
let parts = [];
let urlsP = urls.map((url, index) => {
return dlPart(url, index, tempDir);
});
for (let urlP of urlsP) { // Parallel (yay!)
parts.push(await urlP);
}
ES6 Code
let parts = [];
// Capture all the pending promises into an array
let urlsP = urls.map((url,index)=>{
// Returns the promise to the urlsP array
return dlPart(url,index,tempDir);
});
// Catch all the data in an array
Promise.all(urlsP).then(res=>{
parts=res;
});
To reiterate what Sam has explained the post above.
In the ES7 example the map function calls of all the async functions and creates a new array of promises. The for of loop
iterates through the array of promises and checks to see if the promise has been resolved yet, if it hasn't it will wait until the that specific promise resolves, then repeat this process. If you were able to watch this code in slow motion with a debugger tag in chrome you would notice that some promises will be resolved by the time the loop checks to see if it was resolved, while others you will have to wait for
The ES6 example is essentially the same, with the only difference in how we get the parts array. In this case the Promise all response is an array of all the resolved values, thus we make parts equal to the response instead of pushing into the array
Now imagine writing the following code in es6:
ES7 Code
let index = 0; let parts = [];
for (let url of urls) { // NOT Parallel any more!!!
index++;
parts.push(await dlPart(url, index, tempDir));
}
You would have to use a generator or a recursive function, My understanding of generators is still pretty new so I will show a recursive function
ES5/6 Code
let index = 0; let parts = []; let promises = [];
function getParts(index,){
return new Promise((resolve,reject)=>{
dlPart(urls[index],index,tempDir).then(res=>{
parts.push(res)
if(index<urls.length-1){
promises.push(getParts(++index));
resolve()
}else{
resolve()
}
}
}
}
promises.push(getParts(index));
Promise.all(promises).then(finished=>{
// Then you can continue with whatever code
});
Now with this ES7 example code above you will notice that the for of loop
iterates through the urls array and waits for the promise to resolve before moving to the next index of the array.
The ES6 example does the same in the sense that it will begin with the url at index 0, waits for dlPart
promise to resolve, pushes the response into the parts array, checkes that the index is still smaller than the urls array length, getParts then calls itself again, until finally it runs out of urls indices and resolves its last promise so that the code below the Promise.all(promises)
may begin to run
When you begin looking at the differences in the readability between ES6 and ES7 you can see why async/await were finalized in the es7 spec.