The evaluation strategy of the compiler is usually divided into call by value and call by name. Thunk
function is used to implement call by name in the compiler. It often places the parameters into a temporary function and then passes this temporary function into the body of the function, and this temporary function is called Thunk
function.
The evaluation strategy of the compiler is usually divided into call by value and call by name. In the example below, passing an expression as a parameter, the ways of implementation in call by value and call by name are different.
In the above example, whether using call by value or call by name, the result of the execution is the same, but their calling processes are different:
x + 1
, then pass the calculated result 2
to the s
function, which is equivalent to calling s(2)
.x + 1
expression to y
, and calculate x + 1
when using it, which is equivalent to calculating (x + 1) + 1
.Call by value and call by name each have their own pros and cons. Call by value is relatively simple, but when evaluating parameters, the actual value of the parameter is not used, which may cause unnecessary calculations. Call by name can solve this problem, but the implementation is relatively more complex.
In the above example, the function s
did not use the value obtained from the expression x + 2
. When using call by name, only the expression is passed without being calculated, and it will not be calculated unless it is used in the function. If using call by value, the value of x + 2
will be calculated first and then passed in. If it is not used, then there will be an unnecessary calculation. Thunk
function is designed as an implementation of call by name, often placing the parameters into a temporary function and then passing this temporary function into the body of the function, and this temporary function is called Thunk
function.
The evaluation strategy in Js
is call by value. Using Thunk
functions in Js
needs to be manually implemented and has a different meaning. In Js
, Thunk
function replaces not an expression, but a multi-argument function, by replacing it with a single-parameter version and only accepting a callback function as a parameter.
Implement a simple Thunk
function converter. For any function, as long as the parameters have a callback function, it can be written in the form of a Thunk
function.
It might be that Thunk
functions were not widely used before ES6
; however, after ES6
, Generator
functions appeared, and by using Thunk
functions, they can be automatically used for managing the flow of Generator
functions. Firstly, let's talk about the basic usage of Generator
functions. When calling a generator function, its statements are not executed immediately. Instead, it returns an iterator object that points to the internal state object of the generator. When the next()
method of this iterator is called for the first time (subsequently), its statements execute until the first (subsequent) yield
is encountered. Following a yield
, the iterator returns the value and the pointer starts executing from the beginning of the function or the previous suspended point until the next yield
. Alternatively, if yield*
is used, it indicates the transfer of control to another generator function (pausing the current generator).
Since Generator
functions can temporarily suspend the execution of a function, they can be used with asynchronous tasks. After one task is completed, the next one can continue. The following example demonstrates the synchronization of asynchronous tasks. When the previous delayed timer is finished, the next timer task will proceed. This approach can solve the problem of nested asynchronous tasks. For example, using callbacks, after a network request, adding a callback for the next request can easily lead to callback hell. However, Generator
functions can solve this issue. In fact, async/await
is an asynchronous solution based on Generator
functions and Promise
.
Even though the above example can run automatically, it's not very convenient. Now, let's implement an automatic flow management function using a Thunk
function. This function automatically handles the processing of callback functions. All you need to do in the Thunk
function is pass the parameters required for the function's execution, such as the example's index
. Then, you can write the body of the Generator
function so that the left-hand side variable receives the parameters executed by the Thunk
function. When using the Thunk
function for automatic flow management, you must ensure that yield
is followed by a Thunk
function.
As for the automatic flow management function run
, when the next()
method is called with an argument, this argument is passed to the left-hand side variable of the previous executed yield
statement. In this function, when the next
is first executed without passing any parameters (and there is no receiving variable statement above the first yield
), no parameter needs to be passed. The next step is to determine if this generator function has finished execution. Since it has not finished, the custom next
function is passed into res.value
. It's important to note that res.value
is a function. Executing the commented line below in the example, you can see that this value is f(funct){...}
. By passing the custom next
function, the execution authority is given to the f
function. After this function completes the asynchronous task, the callback function is executed, triggering the next next
method of the generator. This next
method is passed with a parameter, and, as mentioned earlier, passing a parameter transfers it to the left-hand side variable of the previous executed yield
statement. Thus, in this execution, this parameter value is passed to r1
, and then next
continues to be executed repeatedly until the generator function finishes running. This achieves automatic flow management.