【JS】一个函数在setTimeout里调用自身会造成递归吗?
(function repaint(){//重绘相关代码
setTimeout(repaint,16) ;
})() ;
或者
(function repaint(){//重绘相关代码
requestAnimationFrame(repaint) ;
})() ;
我在函数内部加了断点,在chrome里面查看call stack,始终是一层,这是否能证明一个函数,在setTimeout和requestAnimationFrame内调用自己不造成递归?
回答
答案是不会。
首先我们来理解一下什么叫递归,先不贴wiki上的说明了,大家普遍认识是,递归就是函数自身调用自身。这里面很重要的一点就是,在调用自身的过程中,父函数是没有退出的。需要等被调用的子函数退出后父函数才退出。
但是setTimeout函数不是这样执行的,它只是创建了一个定时任务,然后直接退出了,javascript的引擎线程会将这个任务放到自己的定时任务中,当定时结束后才调用子函数。
可以参考下图(来源于网络)
详细可以参考:谈谈JavaScript的异步实现
不会。因为当前函数执行完毕才会去处理超时处理函数。
这个分逻辑上和实现上。
- 逻辑上来说,它和递归是等价的。
- 但是实现上,它是异步执行的,不会导致栈在使用上的无限增加,因为之前的函数执行完就销毁了。
lz可以这么认为,这种异步形式的递归,不会导致栈空间的溢出。但是作为副作用,这种递归不能依靠异步调用的返回值执行操作(当然,后面可以有操作,但是无法利用到返回值)。和尾递归很像呢,至少在逻辑上两者也确实非常接近。
setTimeout是“异步”执行的(在我看来其实是伪异步,JS是单线程的,所谓的异步只是通过适当地插入到代码执行队列中延迟执行而已),其实总体相当于在一段时间内定期执行一次repaint函数而已。只不过第一次是立刻执行罢了。
可以叫循环,但不能叫递归
虽然称不上递归,但还是感觉repaint这个方法会被调用多次的。
每隔一段时间生产一个settimeout对象也会有开销的吧
setTimeout是异步函数无可厚非,执行完当前函数之后把自身当作回调扔给定时器线程就不管了,就好比如repait();dom.onclick=function(){repait()}执行一次后,我每1s后都点击一次让它repait,这不是递归,就是函数的普通调用,下一次的函数作用域里面拿不到上一次函数作用域的变量。如果是fuction repait(a){console.log(a);setTimeout(function(){repait(++a)},1000)},是可以拿到上一次函数作用域的变量,证明还有引用不会销毁,保存在堆中,但是这不就是闭包么?函数内返回一个匿名函数给定时器线程作为回调,这个匿名函数被定时器引用,到时间这个匿名函数执行调用,调用之后创建一个新的匿名函数被引用,上一个匿名函数已经没有引用了,垃圾回收掉了。repait函数每一次都是创建一个新的匿名函数形成闭包,而有外部引用的闭包才不会被销毁。function repait(){return function (){repait()}};var niming1 = repait();var niming2 =niming1();niming1 = null;
以上是 【JS】一个函数在setTimeout里调用自身会造成递归吗? 的全部内容, 来源链接: utcz.com/a/86204.html