In this article I will describe how the ES2017 functions are essentially a play between two older features: and , both of which were added earlier to the language in the ES2016 specification. async JavaScript generators promises Before you start reading .. This article is an introduction to , or functions. not promises generators async The goal of this article is to describe how functions can be realised using and . only async promises generators It does offer any opinion whether functions are better or worse than the other approach. not async The code examples used in this article are ingeniously contrived for easier explanation. They are meant for any serious use. not But why .. ? Since functions are now natively supported, what is the need to understand how they work? async Well, apart from the obvious reason of , an important reason is supporting older platforms. If you want your code using these newer features to run on older browser versions or older Node.js versions, you would be required to use like to transform these newer features into older features. curiosity tools Babel Therefore, a solid understanding of how functions get decomposed into and can come in handy when reading/debugging your transformed code. For example, here is a simple example of an function : async generators promises async This function gets transformed by Babel into the following ES2016 code (don’t worry about understanding it right now, we will cover it later) : Babel output for the previous async function (ES2016) They look really different! However, if you understand how functions actually work, then this transformation is fairly obvious. async Another fun fact, browsers also implement functions in a similar fashion i.e. they the code to use and quite similar to Babel. async transform async generators promises Okay, so how does it happen ? Sometimes in order to understand how something works, the best way is to build it yourself. So let’s flip the question: Imagine we are given a piece of code that uses functions, how can we rewrite it using only and functions? async promises generator Here’s an function : async It performs three asynchronous tasks, one after the other where each task depends on the completion of the previous task. Finally, it returns the result of the last task. How can we write it using generators ? Let’s quickly recap how they work. Here’s a simple generator function : Generators are functions which can be exited and later re-entered. This generator-function has some interesting aspects (lifted from the docs) : gen MDN When a generator function is called, its body is not executed right away. Instead it returns an iterator-object which adheres to the i.e. it has a method. iterator protocol next The only way to execute the body of is by calling the method on its iterator-object. Every time the method is called, its body is executed until the next expression. The value of this expression is returned from the iterator. gen next next [yield](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield) This method also accepts an argument. Calling it with an argument replaces the current expression with the argument and resumes the execution till the next expression. next yield yield To elucidate (very, very crudely) .. A generator-function gets executed (i.e. one yield-expression at a time), by its iterator (the method). yield-by-yield next Every has a → → behaviour, so to say. yield give halt take It out the value of the current yield-expression, to the iterator. gives It then at this point, until the iterator’s method is called again. halts next When the method is called again, it the argument from it and replaces the currently halted yield-expression with it. It then moves to the next . next takes yield You may want to read the above summary again or refer to the amazing MDN docs ! But how does this help us ? By now you would be wondering, how do the generator functions help our situation? We need to model an asynchronous flow where we have to wait for certain tasks to finish before proceeding ahead. But so far in our discussion everything has been synchronous. How can we do that? Well, the most important insight here is that the generator-functions can yield too. promises A function can a (for example an async task), and its iterator can be controlled to for this to resolve (or reject), and then proceed with the resolved (or rejected) value. This pattern of weaving a an iterator with yielded allows us to model our requirement like this : generator yield promise halt promise promises (Notice how this generator function resembles our _async_ function!) But this is only half the story. Now we need a way to execute its body. We need a function that can control the iterator of this function to every time a is yielded and proceeds once it resolves (or rejects). It sounds complicated, but is very simple to implement, as shown below : generator halt promise A function that executes a generator function. (Only for explanation, ) do not use it ! Now we can execute our function using this function as shown below: generator init runner Use `runner` to execute the body of `init`. And that’s it! This combination of a function and our function achieves a similar outcome as the original function. runner generator async Please note that this runner function is only for demonstrating the concept. It is not suitable for any serious use. If you are looking for a proper implementation, you can find it here . To summarise We started with an function and then we wrote an identical implementation using and . That is, the following two pieces of code will have a similar effect : async generators promises Further exercises In the beginning of this article, we looked at how Babel transforms code to ES2016 code using and . You can now revisit that transformed code and compare how our function is similar to the function. In fact, that function is the foolproof version of our extremely simple function. async generators promises runner _asyncToGenerator _asyncToGenerator runner If you are still interested, you can go another step forward i.e. transform functions to ES2015 code i.e. without . For this you would have to emulate themselves (using a stateful busy loop with cases for e.g. see the ). async generators generators switch regenerator project I hope this explanation clears up the mystery behind functions. They offer a simpler syntax and therefore less code noise. The proposal for functions states that : async async The introduction of Promises and Generators in ECMAScript presents an opportunity to dramatically improve the language-level model for writing asynchronous code in ECMAScript. Thanks to , & for providing their feedback to improve this article. Akos Alisa Kristian
Share Your Thoughts