JavaScript
is single-threaded, in order to avoid the negative effects that synchronous blocking may bring, an asynchronous non-blocking mechanism has been introduced. From the earliest callback functions to ES6
's Promise
object and Generator
functions, the solution for asynchronous execution has been improved each time, but there are still some drawbacks. They all have additional complexity and require understanding of the abstract underlying mechanisms until async/await
was introduced in ES7
. It can simplify the synchronous behavior when using multiple Promise
s, and when programming, one may not even need to worry about whether the operation is asynchronous.
Firstly, using async/await
to execute a set of asynchronous operations does not require nested callbacks or writing multiple then
methods. It feels like a synchronous operation, and of course, in actual use, the await
statement should be placed in the try...catch
block because the result of the Promise
object after the await
command may be rejected
.
In fact, async/await
is a syntactic sugar for Generator
functions, similar to how Promises
are similar to structured callbacks. async/await
combines the Generator
and Promise
functions in its implementation. Below, by using Generator
functions and Thunk
functions, a similar example to the one above is implemented. It can be seen that only async
is replaced by *
placed on the right side of the function and await
is replaced by yield
. Therefore, async/await
is actually a syntactic sugar for Generator
functions. The only difference here is that it implements an automatic flow management function run
, whereas async/await
has a built-in executor. More details about the implementation of this example will be discussed below. Comparatively, async
and await
are clearer in their semantics compared to *
and yield
, with async
indicating that the function has asynchronous operations and await
indicating that the expression followed by it needs to wait for a result.
async
functions have a built-in executor that can implement automatic flow management of function execution through Generator yield Thunk
and Generator yield Promise
. It only requires writing the Generator
function as well as the Thunk
function or Promise
object and passing them to a self-executing function to achieve a similar effect to async/await
.
The run
function automatically manages the process. First, it needs to know that when the next()
method is called with a parameter, that parameter will be passed to the variable on the left side of the yield
statement of the previously executed line. In this function, the first time next
is executed without passing a parameter and there is no statement to receive the variable at the first yield
, so no parameter needs to be passed. Next, it is to determine whether the generator function has finished executing. In this case, it has not finished executing, so the custom next
function is passed into res.value
. It is important to note that res.value
is a function. In the example below, the commented line can be executed, and then you can see that the value is f(funct){...}
. At this point, after passing the custom next
function, the execution permission of next
is transferred to the function f
. After this function completes the asynchronous task, it will execute a callback function. In this callback function, the next next
method of the generator will be triggered, and this next
method is passed with a parameter. As mentioned earlier, when a parameter is passed, it will be passed to the variable on the left side of the yield
statement of the previously executed line. Therefore, in this execution, this parameter value will be passed to r1
, and then next
will continue to execute, repeatedly, until the generator function finishes running, thereby achieving automatic process management.
Compared to using the Thunk
function for process automation, using Promise
to achieve it is relatively simpler. A Promise
instance can know when the last callback was executed, and through the then
method, it starts the next yield
, continuing the execution, thus achieving automatic process management.