Collections, Generators, and Promises
Table of Contents
Introduction
Long ago, the council decided that Collections and Generators we’re necessary for ECMAScript 2015. Along with Map, Set, Weakmap, and WeakSet. But this article is focused on the first two, and combining them with Promises practically.
What are they?
Generators are functions that can be paused and resumed. They we’re introduced because it makes it easier for us to manage and understand asynchronous operations like fetching data from a server or waiting for user input. Because we’re allowed to pause and resume the execution of a function, we can write asynchronous code in a more sequential and intuitive way.
While Collections are a group of data structures to work with collections of data more efficiently. Some of this was covered previously my last article. But not, working with Sets. Sets and Maps are part of then-2015 introduced Collections data structures. They help us write more refined and deal with common data-related tasks.
Promises are functions that can represent two states, either complete or failure. It helps us deal with the period in which we’re waiting for something to happen, and let’s us avoid the headache of nested callbacks It’s useful to solve the racing condition problem as a by-product of concurrent programming challenges.
Generators and Collections
"use strict";
// Define artworks collection generator function
// Define genres collection generator function
// Create collections using generators
;
;
// Function to display artworks
// Function to display genres
// Explicitly iterate through artworks collection using next()
"Artworks Collection:";
;
while !nextArtwork.done
// Explicitly iterate through genres collection using next()
"Genres Collection:";
;
while !nextGenre.done
Above, we are using generators to create lists of artworks and art genres for an virtual art exhibition. The generateArtworks
function lists famous paintings with details like title, artist, and year, while generateGenres
lists different types of art styles. When we call these functions, they give us one item at a time working with yield
.
We start by printing “Artworks Collection:” and then get to the first artwork using artworksCollection.next()
. Which will give us an object with the artwork and a done
property. We show the artwork using displayArtwork
and keep getting the next artwork until done
is true
, meaning there are no more artworks.
We do the same for genres, printing “Genres Collection:” and getting each genre with genresCollection.next()
, showing it with displayGenre
, and repeating it until there are no more genres. It allows us to use yield
and next()
to handle one item at a time from the list. Which makes it easy to manage large collections without loading everything at once.
Promises
"use strict";
// Same code as before...
// Function to fetch and display dog images
// Wrapper generator function to control execution flow
// Start the exhibition flow
;
Above, we control the asynchronous art exhibition flow using generators and promises. The fetchDogImages
function first uses fetch
to retrieve dog image URLs as a promise, then uses await
to wait for the response before converting it to JSON. It iterates through the URLs and logs them.
The important part lies in how the control flow is directed in the exhibitionFlow
generator function. Immediately, it prompts the user for displaying the “Dog Artwork” section. If the user agrees (y), it calls fetchDogImages
using yield await
.
yield
then pauses the generator until the dog image fetching is complete, then continues execution. Otherwise, it skips the dog artwork section.
The flow then continues by iterating through two separate iterators (artworksCollection
and genresCollection
) using a loop with for await...of
.
In each iteration, it retrieves the next artwork/genre using next()
, and displays it using the appropriate functions (displayArtwork
or displayGenre
), and repeats until the iterators are altogether exhausted.
Benefits
Like in our example, promises are able to handle asynchronous operations like fetching images, while waiting for a certain action to occur or data before proceeding.
Generators meanwhile control the flow by pausing execution at yield points, allowing for a more structured and readable way to manage asynchronous steps within the exhibition flow.
Conclusion, considerations
The practical performance cost with CPU’s that can process trillions of operations per second is negligible and we shouldn’t really worry about that since the performance cost is trivial. Even while resuming and pausing generators. This works similarly to our brain. Similar to the psychological concept of set-shifting.
Combining promises, generator functions, and collections let us sequentially handle asynchronous tasks while preserving control flow clarity despite JavaScript’s asynchronous nature.
Of course, there is more to this topic than what I wrote above, for more references checkout the below. As always, I hope you have a great day!