DEV Community

Cover image for Creating the typewriter effect with the use of async generators
John Kapantzakis
John Kapantzakis

Posted on

Creating the typewriter effect with the use of async generators

In this post, we are going to present the process of creating the typewriter effect.

The following codepen illustrates the final result.

Our goal

The functionality we want to achieve is a subset of another library (with more options and methods) called text-typing, that I have developed. It is in beta version yet, but available as npm package for anyone who would like to experiment with some of its capabilities.

You can find text-typing here:

GitHub logo kapantzak / text-typing

Simple typewriting effect

npm version

text-typing

A tool for creating typewriter effect, with a simple, promise based api.

text-typing gif

Installation

Install npm package

npm

npm install text-typing

yarn

yarn add text-typing

And then import the package

import {textTyping} from "text-typing"

Usage

All you need to do is to initialize the tool, passing a reference to an existing DOM element, and start typing!

HTML

<h1 id="myHeading"></h1&gt

JS

(async () => {      
  const txt = textTyping(document.getElementById("myHeading"));
  await txt.typeText("Hello");
})();    

Chaining methods

You can call multiple methods on the same instance, either by using await (inside an async function), or by using then after a method call

await
(async () => {      
  const txt = textTyping(elem);
  await txt.typeText("Hello");
  await txt.backspace(2);
})();
then
(() => {
  const txt = textTyping(elem);
  txt.typeText("Hello").then(resp => {
    resp.backspace(2);
  });
})();

Options

speed

The typing speed that is going to be used by called methods, if no specific speed is provided to the specific method.

For this post, we are going to develop a function that exposes a small api (one method 😋) which then, we can call in order to apply the typewriter effect. This function will take two parameters:

  • The text to be typed
  • An array of of two numbers that is going to be used as the speed range of the typing process

The call is going to be like that:

const textHolder = document.getElementById("myTextHolder");
const speedRange = [100, 600];
const txt = textTyping(textHolder, speedRange);
txt.typeText("Hello there!");
Enter fullscreen mode Exit fullscreen mode

The markup

For start, we need a HTML element to use it as our text holder. Lets use a <div> element with id myTextHolder, nested in another div element that is going to be used as the wrapper element.

Then, we apply some css to verticaly allign our text (not necessary).

The JS part

We can now begin writing our js functions, starting with the main function that we are goint to call in order to apply the typewriter effect.

We declare the textTyping function that takes two arguments

  • elem: the HTML element to hold the text
  • speedRange: the speed range that is going to be used

Blinking cursor

We are developing a typewriting effect, so, we need to display a blinking cursor. For that, we create a <span> element and we apply some css animations in order to achieve the blinking effect.

We create the cursor as soon as we call the textTyping function:

and we apply the respective css:

API

Now we are going to expose our simple api, which consists of one method, the typeText method! To achieve that, we return an object that has a property named typeText and a value of an anonymous function that takes one argument, named text.

In addition, we have added another <span> element (section) that serves the role of an inner text holder, in order to separate the cursor from the text.

Typing process

Now we have to implement the typing process. Lets try by spliting the text and getting an array of letters. We can iterate this array and insert each letter inside the section element one by one.

Furthermore, we need to inject a timeout before each letter injection, based on the speedRange parameter provided to textTyping function.

Lets declare a function that takes the speedRange array and returns a random number inside the two numbers contained in the array:

Here is our first (not successful) attempt

What happened? Why are letters mixed up?

The problem is here

The for loop instantly iterates the letters array and the setTimeout callbacks start to execute at a random time from the loop execution end.

Each setTimeout does not wait for the previous timeout callback to be called, as javascript has a non-blocking runtime. On the contrary, each setTimeout, instantly pushes a callback to the message queue with a random timeout generated by getSpeed function.

For more details about asynchronous execution, you can checkout this article about the event loop.

Async generators

In order to solve our problem, we need to find a way to, correctly iterate over a sequence of asynchronous tasks.

Async generators come to our resque!

We are not going to get into more detail about async generators or async iterators. For now, we only need to know that async generators provide us with the ability to generate sequences of asynchronous data, that can be iterated and procude the desired outcome.

Now lets apply them to our function.

First, we need to declare a function that returns a Promise which gets resolved after a certain amount of time, returning the appropriate letter for us.

We are going to call this function inside our async generator as shown in the following gist:

Note the function* statement, this is the way we declare generators. And because we want an async generator, we prepend the async keyword (in fact async is not a keyword itself, instead, the combination async function is).

All we have to do now is to iterate over the sequence that our async generator produces. We can do that with the use of the for await ... of statement like this:

We now have the desired result, as shown in the codepen at the begining of the post.

Thanks for reading 🤗 so far! I hope it was interesting enough! Please leave your comments for any feedback or questions!

Resources

Top comments (0)