前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >图解尾调用优化

图解尾调用优化

作者头像
JS菌
发布2019-04-10 15:32:12
4420
发布2019-04-10 15:32:12
举报
文章被收录于专栏:JS菌JS菌

Photo by Benni Asal on Unsplash

尾调用

啥是尾调用?

尾调用就是函数的最后一个步骤调用另一个函数

比方说:

20190307171547.png

函数在调用的时候会在调用栈中 push 一个调用帧,每次执行完函数都会逐一弹出调用帧知道所有函数执行完毕,调用栈被清空:

调用栈中的同步代码

代码语言:javascript
复制
1function f1() { console.log('?') }
2function f2() { f1() }
3function f3() { f2() }
4
5f3()

调用栈如下图:

  • 首先执行 script ,将 main 主程序推入调用栈中并执行,发现需要调用 f3
  • 将 f3 函数推入调用栈中,执行 f3,发现需要调用 f2
  • 将 f2 函数推入调用栈中,执行 f2, 发现需要调用 f1
  • 将 f1 推入调用栈中,执行 f1,发现需要调用 console.log 方法
  • 推入 console.log 并打印结果执行完毕
  • 弹出 consoole.log
  • 弹出 f1
  • 弹出 f2
  • 弹出 f3
  • 弹出 main,代码执行完毕

调用栈中的异步代码

以 setTimeout 为例:

代码语言:javascript
复制
1console.log('1')
2setTimeout(function() {
3    console.log('3)
4}, 5000)
5console.log('2')
6

调用栈见下图:

执行代码推入 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 并打印 3
  • 最后将 console.log 弹出调用栈,代码执行完毕

尾调用优化

每次在函数被调用的时候,内存都会保存调用帧。尾调用因为是函数的最后一步,因此并不需要外层函数的调用帧。我们只需要将最后需要执行另外一个函数之前用 return 操作符显式表明"不再需要此函数"即可

20190309013011.png

before

20190309013038.png

after

注意必须使用严格模式

在执行过程中,调用栈的调用帧永远只有一条,这样就可以节省很大一部分内存

参考:

  • https://vaibhavgupta.me/2018/01/20/understanding-event-loop/
  • http://www.ruanyifeng.com/blog/2015/04/tail-call.html
  • https://juejin.im/post/5acdd7486fb9a028ca53547c
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-03-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 JS菌 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 尾调用
  • 尾调用优化
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档