圖解尾調用優化
尾調用
啥是尾調用?html
尾調用就是函數的最後一個步驟調用另外一個函數異步
比方說:函數
函數在調用的時候會在調用棧中 push 一個調用幀,每次執行完函數都會逐一彈出調用幀知道全部函數執行完畢,調用棧被清空:oop
調用棧中的同步代碼post
function f1() { console.log('🍎') }
function f2() { f1() }
function f3() { f2() }
f3()
調用棧以下圖:優化
- 首先執行 script ,將 main 主程序推入調用棧中並執行,發現須要調用 f3
- 將 f3 函數推入調用棧中,執行 f3,發現須要調用 f2
- 將 f2 函數推入調用棧中,執行 f2, 發現須要調用 f1
- 將 f1 推入調用棧中,執行 f1,發現須要調用 console.log 方法
- 推入 console.log 並打印結果執行完畢
- 彈出 consoole.log
- 彈出 f1
- 彈出 f2
- 彈出 f3
- 彈出 main,代碼執行完畢
調用棧中的異步代碼spa
以 setTimeout 爲例:code
console.log('1')
setTimeout(function() {
console.log('3)
}, 5000)
console.log('2')
調用棧見下圖:htm
- 執行代碼推入 script 代碼 main 並執行,發現須要執行 console.log
- 將 console.log 推入調用棧
- 執行 console.log 打印 1 彈出調用棧
- 發現 setTimeout 將等待執行的回調函數推入宏任務列表,將 setTimeout 彈出調用棧
- 繼續執行代碼發現須要執行 console.log 將任務推入調用棧
- 執行 console.log 打印 2 並彈出調用棧
- script 代碼 main 執行完畢,彈出調用棧
- 同步代碼執行完畢,查看宏任務列表發現須要執行 console.log
- 延遲 5s 將 console.log 推入調用棧
- 執行 console.log 並打印 2
- 最後將 console.log 彈出調用棧,代碼執行完畢
尾調用優化
每次在函數被調用的時候,內存都會保存調用幀。尾調用由於是函數的最後一步,所以並不須要外層函數的調用幀。咱們只須要將最後須要執行另一個函數以前用 return 操做符顯式代表"再也不須要此函數"便可blog
before
after
注意必須使用嚴格模式
在執行過程當中,調用棧的調用幀永遠只有一條,這樣就能夠節省很大一部份內存
參考: