You can work with Javascript as a functional programming language. If you do not like it, you can also build your application object-oriented also with JavaScript. Perhaps it is for this reason that the JavaScript syntax itself contains a lot of syntactic sugar.
Syntactic sugar
Understanding simple syntactic sugar can be considered as a syntax to help you write code faster or just to fit and closer to a certain programming style that you choose. To give an example of this, we will look at ways to create an object in JavaScript. If you’re a fan of functions, this might be your option:
1 2 3 4 5 6 | <span class="token keyword">function</span> <span class="token function">Animal</span> <span class="token punctuation">(</span> name <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> name <span class="token operator">=</span> name <span class="token punctuation">}</span> dog <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Animal</span> <span class="token punctuation">(</span> <span class="token string">'Puppy'</span> <span class="token punctuation">)</span> |
But if you are an OOP lover, don’t worry because you can still do what you want:
1 2 3 4 5 6 7 8 | <span class="token keyword">class</span> <span class="token class-name">Animal</span> <span class="token punctuation">{</span> <span class="token function">constructor</span> <span class="token punctuation">(</span> name <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> name <span class="token operator">=</span> name <span class="token punctuation">}</span> <span class="token punctuation">}</span> dog <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Animal</span> <span class="token punctuation">(</span> <span class="token string">'Puppy'</span> <span class="token punctuation">)</span> |
The two writing styles are completely different but give the same results and that can be considered as a syntactic sugar. As you know, in JavaScript there is no class concept, all you see really looks like the syntax of an object-oriented language like Java, C # … but what is hidden beneath What is still ubiquitous in JavaScript is the function. If you are still wondering:
1 2 | <span class="token keyword">typeof</span> Animal <span class="token comment">//=> "function"</span> |
Why did I mention syntactic sugar, which sounds like nothing to do with the title of the post? But don’t be in a hurry because before going to async / await we will have to find out about something else that sounds even more unrelated. That is the generator function.
Generator Function
With a normal function, the code inside it will be run sequentially, when the last line of code is executed, at the same time that function ends. A generator function is different, it can run many times, rather it can run and then pause but then run again. Let’s take a look at the example below to see the difference:
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token keyword">function</span> <span class="token function">infinityLoop</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> i <span class="token operator">=</span> <span class="token number">0</span> <span class="token keyword">while</span> <span class="token punctuation">(</span> <span class="token boolean">true</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> i <span class="token operator">++</span> <span class="token punctuation">}</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> <span class="token string">'Finish loop...!'</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token function">infinityLoop</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> |
This is a normal function and if you try to run that code on your browser, it probably won’t take long for your browser to freeze and sometimes you can’t even turn it off. But with a generator function:
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token keyword">function</span> <span class="token operator">*</span> <span class="token function">infinityLoop</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> i <span class="token operator">=</span> <span class="token number">0</span> <span class="token keyword">while</span> <span class="token punctuation">(</span> <span class="token boolean">true</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">yield</span> i <span class="token operator">++</span> <span class="token punctuation">}</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> <span class="token string">'Finish loop...!'</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> infinity <span class="token operator">=</span> <span class="token function">infinityLoop</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> |
As you can see, the syntax of a generator function is nothing special except the *
and yield
keyword. And there won’t be any problems with your browser if the above code is run because when you call a genarator function, what you get is just a Generator Object.
1 2 | <span class="token keyword">typeof</span> infinity <span class="token comment">//=> "object"</span> |
So what is this object special:
1 2 3 4 | infinity <span class="token punctuation">.</span> <span class="token function">next</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token comment">//=> {value: 0, done: false}</span> infinity <span class="token punctuation">.</span> <span class="token function">next</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token comment">//=> {value: 1, done: false}</span> infinity <span class="token punctuation">.</span> <span class="token function">next</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token comment">//=> {value: 2, done: false}</span> |
This is exactly how a genarator works. Each time you call the next
function, the generator will be executed, when met yield
keyword it will return an object containing two properties:
- value: The value to the right of
yield
is returned - done: The status of the generator, if it is
true
it means that the generator has finished running, otherwise it isfalse
The generator will now go into hibernation, it waits until it is called again. Returning to the example above, we have an infinite while
loop and a variable i
whose value is incremented after each loop. The problem is that we never fall into that infinite loop, but only after calling infinity.next()
, a new loop is executed. So somehow, the value of i
is saved and will increase after each call. In this case, that value will increase indefinitely and we will never see the Finish loop...!
printed to the screen.
In another example:
1 2 3 4 5 6 7 8 9 10 | <span class="token keyword">function</span> <span class="token operator">*</span> <span class="token function">sayHello</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> name <span class="token operator">=</span> <span class="token keyword">yield</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> <span class="token string">'Hello '</span> <span class="token operator">+</span> name <span class="token punctuation">)</span> <span class="token punctuation">}</span> hello <span class="token operator">=</span> <span class="token function">sayHello</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> hello <span class="token punctuation">.</span> <span class="token function">next</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token comment">//=> {value: undefined, done: false}</span> hello <span class="token punctuation">.</span> <span class="token function">next</span> <span class="token punctuation">(</span> <span class="token string">'Lam'</span> <span class="token punctuation">)</span> <span class="token comment">//=> Hello Lam {value: undefined, done: true}</span> |
As you can see, the next
function can take a value and this value will then be assigned to yield
. Thus, you can see, yield
throws the value to its right and receives the value passed from next
.
In a nutshell, the difference between a genarator function and a normal function is that it can pause the execution and then execute it again, returning different results at different times.
Async / await
Before getting to the main point, let’s see what the following two code snippets have in common:
- Async Function
1 2 3 4 5 6 7 | <span class="token keyword">async</span> <span class="token function">getUsers</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> url <span class="token operator">=</span> <span class="token string">'https://reqres.in/api/users'</span> <span class="token keyword">let</span> users <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span> <span class="token punctuation">(</span> url <span class="token punctuation">)</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> <span class="token string">'Users: '</span> <span class="token punctuation">,</span> users <span class="token punctuation">)</span> <span class="token punctuation">}</span> |
- Genarator Function
1 2 3 4 5 6 7 | <span class="token keyword">function</span> <span class="token operator">*</span> <span class="token function">getUsers</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> url <span class="token operator">=</span> <span class="token string">'https://reqres.in/api/users'</span> <span class="token keyword">let</span> users <span class="token operator">=</span> <span class="token keyword">yield</span> <span class="token function">fetch</span> <span class="token punctuation">(</span> url <span class="token punctuation">)</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> <span class="token string">'Users: '</span> <span class="token punctuation">,</span> users <span class="token punctuation">)</span> <span class="token punctuation">}</span> |
Looking at this we will see async
seems to be a function*
and await
could be yield
. So async/await
is it a syntactic sugar and behind that shell is Genarator Function? The best way to get an answer is to use a genarator function and make it act like an async function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token keyword">function</span> <span class="token function">runGeneratorLikeAsyncAwait</span> <span class="token punctuation">(</span> generator <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> generatorObject <span class="token operator">=</span> <span class="token function">generator</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">function</span> <span class="token function">loopUntilDone</span> <span class="token punctuation">(</span> value <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> next <span class="token operator">=</span> generatorObject <span class="token punctuation">.</span> <span class="token function">next</span> <span class="token punctuation">(</span> value <span class="token punctuation">)</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> next <span class="token punctuation">.</span> done <span class="token punctuation">)</span> <span class="token keyword">return</span> next <span class="token punctuation">.</span> value <span class="token punctuation">.</span> <span class="token function">then</span> <span class="token punctuation">(</span> loopUntilDone <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token function">loopUntilDone</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> |
The ideas and functions of the above function are:
- Get into a genarator function.
- Generate generator object from that genarator function.
- Call next on generator object until done status is true
- Because the yield value is a promise, the value passed to next will be the value of the previous next call.
Now it’s time for us to check the results:
- Run Async
1 2 | <span class="token keyword">await</span> <span class="token function">getUsers</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> |
- Run Genarator
1 2 | <span class="token function">runGeneratorLikeAsyncAwait</span> <span class="token punctuation">(</span> getUsers <span class="token punctuation">)</span> |
Certainly, there will be no difference when we execute the two pieces of code above.
Summary
There are lots of interesting things in Javascript, but sometimes it can make you unable to understand what’s going on. But most likely, your problem is not quite as complex as you think it is, but merely a variation of something that is so familiar to you. Like promises or async / await, they are not something new that we already know, except that they are cleverly hidden by JavaScript underneath that neat cover.
Source of the article: https://www.dnlblog.com/posts/ben-rong-async-await-co-gi