Can you implement an async-await function with just 20 lines of code?
Tags: JavaScript, Software Development, Asynchronous, Programming, Web Development

Can you implement an async-await function with just 20 lines of code?

One thing that will make you stand out in an interview

Photo by Moritz Kindler on Unsplash

If the interviewer asked you to write an async function by hand, would you be able to complete the task?

The async function is the syntax sugar of the generator function. In this article, I will first examine how the async keyword and the generator function work together to manage asynchronous programming. Then I’ll work with you to implement a simple async function using the generator function.

First, let’s look at a function that uses the async/await keyword.

const getData = () => new Promise(resolve => setTimeout(() => resolve("data"), 1000)) async function test() {

const data = await getData()

console.log('data: ', data);

const data2 = await getData()

console.log('data2: ', data2);

return 'success'

} // The function will print `data` after 1 second, then `data2` after another second and then 'success'

test().then(res => console.log(res))

If we want to express the example above using the generator function, how should we write the code?

We can write it like this:

const getData = () => new Promise(resolve => setTimeout(() => resolve("data"), 1000)) function* testG() {

// await is translated as yield

const data = yield getData()

console.log('data: ', data);

const data2 = yield getData()

console.log('data2: ', data2);

return 'success'

}

As we know, the generator function does not execute automatically. Each time its next method is called, the program stops at the next yield.

With this feature, we can write an automatically executed function and have the generator function fully implement the async function.

function asyncToGenerator(fn){

// ...

}



var test = asyncToGenerator(

function* testG() {

// await is translated as yield

const data = yield getData()

console.log('data: ', data);

const data2 = yield getData()

console.log('data2: ', data2);

return 'success'

}

) test().then(res => console.log(res))

Well, we haven’t written the asyncToGenerator function yet, but the overall idea is set. AsyncToGenerator should accept a generator function and return a promise object. The key here is that the function uses yield to partition asynchronous processes, so how should this be automated?

Before writing this function, we simulated manually calling the generator function and then walked through the process step by step, which helped us think better later.

function* testG() {

const data = yield getData()

console.log('data: ', data);

const data2 = yield getData()

console.log('data2: ', data2);

return 'success'

}

We first call testG to generate an iterator:

// An iterator is returned

var gen = testG()

Then execute next for the first time:

// After the first call `next`, the program stays at the first yield

// The return promise object contains the data needed for `data`

var dataPromise = gen.next()

A promise is returned, which is the promise returned by the first execution of getData() .

const data = yield getData()

But note: this code is cut into left and right parts, and the first call to next is really just a stop at yield getData() , where the value of the data is not determined.

So when is the value of data determined? On the next call to next , the parameters passed in are accepted as values before the last yield.

That is, when we call gen.next(‘a value to data’) again, the value of the data will be determined as ‘a value to data’ .

gen.next(' a value to data ') // This is when the data is assigned

const data = yield getData() console.log('data: ', data); // Then go to next yield

const data2 = yield getData()

This is a difficult point for the generator function to understand, but we have to learn it in order to achieve our goal.

With this feature, we can control the process of yield and then implement the asynchronous function.

Such a function call, which looks like a callback hell, lets async/await be implemented via the generator function.

This is our final code in 22 lines:

Then let’s analyze this code:

`

A note from JavaScript In Plain English

We have launched three new publications! Show some love for our new publications by following them: AI in Plain English, UX in Plain English, Python in Plain English — thank you and keep learning!

We are also always interested in helping to promote quality content. If you have an article that you would like to submit to any of our publications, send us an email at submissions@plainenglish.io with your Medium username and we will get you added as a writer. Also let us know which publication/s you want to be added to.