Diagram tail call optimization

The tail call

What is a tail call?

A tail call is when the last step of a function calls another function

For example:

When a function is called, it pushes a call frame in the call stack. After each function is executed, call frames pop up one by one until all functions are executed and the call stack is cleared:

Call the synchronous code in the stack

function f1() { console.log('🍎')}function f2() { f1() }
function f3() { f2() }

f3()
Copy the code

The call stack is shown below:

  • Script is executed, the main program is pushed onto the call stack and executed, and f3 is called
  • Push the f3 function onto the call stack, execute f3, and find that F2 needs to be called
  • Push the f2 function onto the call stack, execute f2, and find that f1 needs to be called
  • Push f1 onto the call stack, execute f1, and find that you need to call the console.log method
  • Log and print the result
  • Pop-up consoole. The log
  • Pop-up f1
  • Pop-up f2
  • Pop-up f3
  • Main pops up, and the code completes

Call asynchronous code on the stack

Take setTimeout as an example:

console.log('1')
setTimeout(function() {
    console.log('3)
}, 5000)
console.log('2')
Copy the code

The call stack is shown below:

  • The execution code pushes the script code main and executes, and finds that console.log needs to be executed
  • Push console.log onto the call stack
  • Execute console.log to print 1 the call stack is displayed
  • Notice that setTimeout pushes the callback function waiting to execute into the macro task list and pops setTimeout out of the call stack
  • As you continue to execute the code, you find that you need to execute console.log to push the task onto the call stack
  • Execute console.log to print 2 and pop up the call stack
  • The script code main is executed, and the call stack pops up
  • After the synchronization code is executed, you can view the macro task list and find that console.log needs to be executed
  • Delay pushing console.log onto the call stack for 5 seconds
  • Execute console.log and print 2
  • Finally, the console.log is popped onto the call stack and the code is executed

Tail-call optimization

Memory holds the call frame each time a function is called. The last call does not require a call frame for the outer function because it is the last step of the function. We just need to explicitly say “this function is no longer needed” with the return operator before we finally need to execute another function

before

after

Note that strict mode must be used

During execution, the call stack always has only one call frame, which saves a lot of memory

Reference:

  • https://vaibhavgupta.me/2018/01/20/understanding-event-loop/
  • http://www.ruanyifeng.com/blog/2015/04/tail-call.html
  • https://juejin.cn/post/6844903590033621006