I am creating this post as notes from Wes Bos Javascript course which you can sign up for and do with me here: https://beginnerjavascript.com/. Here is a link to Wes' GitHub readme.md.
Sidebar, the formatting is intentionally different between this article and the last one, while I nail down with intention which one I prefer. I'd love to hear your preference in the comments or on twitter!
Drew K
In today's article, we are going to create the ability to "type" font on the screen one character at a time using async, await, & recursion. On the homepage of codingwithdrew.com you can see this in action in the "hero section".
// Create The Project
Create a project folder and within it add an HTML file with this template:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Type Me</title> <style> h2 { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; font-size: 50px; letter-spacing: -0.5px; } </style> </head> <body> <h2 data-type data-type-min="100" data-type-max="300">This text will be typed</h2> <h2 data-type data-type-min="20" data-type-max="80">This text will be typed faster</h2> <h2 data-type>This text will be typed the default speed</h2> <p data-type data-type-min="1" data-type-max="6">Lorem, ipsum dolor sit amet consectetur adipisicing elit. Facere aut error assumenda quod quasi totam est officiis! Facilis eum quaerat vero, natus, odio quia, necessitatibus nam cumque est molestiae perspiciatis ratione fugiat ea nihil voluptatem suscipit. Iusto assumenda omnis beatae dolorum. Placeat molestiae non, reprehenderit repellat, omnis itaque odio aspernatur laborum nostrum similique provident dicta eligendi vitae suscipit. Sapiente voluptatem accusamus enim, eos soluta modi cum nesciunt omnis deleniti perspiciatis commodi necessitatibus accusantium ab nemo possimus, deserunt recusandae molestias adipisci nam harum delectus ex. Sit molestias molestiae aliquam natus hic ipsam ea ipsum reiciendis, odio eos rerum voluptatibus veritatis repellendus eligendi ex officiis, aperiam, fugiat perferendis? Aspernatur consequatur reiciendis laborum velit recusandae iure, in excepturi incidunt accusamus, maxime rem iusto sequi voluptate ducimus, veniam magnam? Sunt similique quasi earum omnis sapiente quisquam, in molestiae, nostrum, excepturi iste tenetur magnam? Unde ipsum maiores eligendi deleniti at eum soluta quisquam quasi blanditiis asperiores. Totam natus commodi sint nesciunt voluptates inventore explicabo architecto neque illo quas, ducimus dignissimos, reiciendis perspiciatis facere dolorem perferendis quasi. Dolorum ad facere sint, aspernatur vero saepe accusantium laudantium reiciendis asperiores fuga ut doloremque hic iusto natus inventore vitae, at esse, odit veniam debitis qui commodi delectus dolore libero! Itaque totam, assumenda quisquam labore illum accusantium exercitationem obcaecati quas animi iusto, saepe voluptate deleniti modi eaque delectus ullam, tempore sequi nemo odio incidunt ea odit magnam nisi! Atque, rem! Enim expedita laudantium reiciendis dolorum vitae ullam deserunt nemo sit. Ex illum ullam repudiandae aliquid et vel, itaque dolore, architecto, sequi ratione eveniet facere recusandae sapiente a soluta! Cupiditate nam sint iusto non debitis cum, unde modi? Omnis nisi, libero tempora obcaecati ad voluptas facilis culpa accusamus dolorum illo fugiat maxime! Odit nulla ullam, praesentium reiciendis aliquid voluptatibus quidem magni fuga libero, repudiandae fugit architecto maiores tempore reprehenderit, optio id eaque repellendus. Sunt accusamus rerum in expedita. Laudantium optio ipsum sapiente atque blanditiis, natus, accusamus temporibus quidem, minima eligendi eos numquam. Eos distinctio doloremque corporis, quo repellendus earum vel reiciendis repellat porro quaerat voluptates nihil natus error? Rerum est praesentium sed earum error molestias officiis modi, natus asperiores impedit reiciendis nihil dolores. Commodi atque repellat quaerat sequi? Est debitis eveniet id rem aperiam nulla molestiae in iure illum laborum tempora praesentium a unde quibusdam cumque accusamus, voluptatem totam tenetur suscipit esse repellendus explicabo eius? Autem eius ea exercitationem assumenda, laboriosam nam ut odit soluta enim sint praesentium, obcaecati nostrum ad.</p> <script src="scripts.js"></script> </body> </html>
Now, create a script.js
file that we will use to build our application.
// Wait Function
To start, let's create our "wait" function again from our last article about async & await.
function wait(ms=0){ return new Promise(resolve => setTimeout(resolve, ms)); };
The above snippet will allow us to run some variation of await wait (10)
later.
Next, we are going to write a function to resolve a random number between any two inputs.
Create a function for getRandomBetween
that carries 3 arguments. The first being a minimum value, the 2nd being a maximum value, then the 3rd being a truly random number with defaults on all 3 that if left blank will automatically have a value between 0 and 100.
function getRandomBetween(min =20 , max = 150, randomNumber = Math.random()){ return Math.floor(randomNumber * (max - min) + min; };
In the console if you run getRandomBetween(0, 100);
which should resolve any number between 0 & 99.999... repeating. But, if we use getRandomBetween(0, 100, 20);
, the 3rd value is passed will eliminate any actual random number for testing purposes unless left blank.
// Async Await For Of Loop (no recursion)
Letter by letter we are going to write in the contents of the element we selected using recursion using a "for of" loop.
//ASYNC AWAIT FOR OF LOOP async function draw(element){ console.log(element); const text = element.textContent; let soFar = ''; for(const letter of text){ console.log(letter); soFar =+ letter; console.log(soFar); element.textContent = soFar; await wait(10); }; };
Let's make this a little more human by adding that random number we created before.
//ASYNC AWAIT FOR OF LOOP async function draw(element){ console.log(element); const text = element.textContent; let soFar = ''; for(const letter of text){ console.log(letter); soFar =+ letter; console.log(soFar); element.textContent = soFar; const {typeMin, typeMax} = element.dataset; const ammountOfTimeToWait = getRandomBetween(typeMin, typeMax); await wait(ammountOfTimeToWait); }; };
// Recursion
If you weren't already familiar with recursion in Javascript, it's the ability to solve problems with smaller sub-problems in a function that calls itself. Well, that's confusing right? Let's explain that a little further using a project that will display text on the browser as if it were being typed out, one letter at a time.
Create an element that takes the element and draws it out one character at a time.
We can create a selector to grab all the data-type
attributes and then loop over every letter in the string. This will repeat, over and over - known as "recursive" code.
//Selector const element = document.querySelectorAll('[data-type]'); element.forEach(element => draw(element);
This can be shortened even further by removing the variable, removing the arrow function, and combining the 2 statements like this:
//Selector document.querySelectorAll('[data-type]').forEach(draw);
We are going to create an async function that draws the element and then uses an index to select the text. We are going to comment out our original draw()
function and replace it with this. Inside of the async function we are gong to call another function that will call the letters over and over. Part of the recursion format is for the function inside the function to call itself, let's look at that.
//RECURSION function draw(element){ let index = 1; const text = element.textContent; const{ typeMin, typeMax } = element.dataset; async function drawLetter(){ element.textContent = text.slice(0, index); index ++; drawLetter(); }; // when runs, kick off drawLetter drawLetter(); };
The above will likely cause your CPU fan to turn on and crash your browser because this is an infinitely loop. To avoid this, we have to create an exit condition.
//RECURSION function draw(element){ let index = 1; const text = element.textContent; const{ typeMin, typeMax } = element.dataset; async function drawLetter(){ element.textContent = text.slice(0, index); index ++; const {typeMin, typeMax} = element.dataset; const ammountOfTimeToWait = getRandomBetween(typeMin, typeMax); await wait(ammountOfTimeToWait); if (index <= text.length) { drawLetter(); }; }; // when runs, kick off drawLetter drawLetter(); };
the final result will look like the gif at the top of this page.
Final Thoughts & My Ask
If you followed this project tutorial, then you just learned how to create a recursive function - that is a function that calls itself from inside another function that will repeat to infinity or until an exit is created to stop the process.
If you found this article helpful, share/retweet it and follow me on twitter @codingwithdrewk! There is so much more in Wes' courses I think you will find valuable as I have. I'm learning so much and really enjoying the course, Wes has an amazingly simple way to explain the difficult bits of Javascript that other courses I've taken could only wish. You can view the course over at WesBos.com. (I am in no way getting any referrals or kickbacks for recommending this)
Drew is a seasoned DevOps Engineer with a rich background that spans multiple industries and technologies. With foundational training as a Nuclear Engineer in the US Navy, Drew brings a meticulous approach to operational efficiency and reliability. His expertise lies in cloud migration strategies, CI/CD automation, and Kubernetes orchestration. Known for a keen focus on facts and correctness, Drew is proficient in a range of programming languages including Bash and JavaScript. His diverse experiences, from serving in the military to working in the corporate world, have equipped him with a comprehensive worldview and a knack for creative problem-solving. Drew advocates for streamlined, fact-based approaches in both code and business, making him a reliable authority in the tech industry.