为什么代码中使用IIFE会导致setTimeout的运行结果产生巨大差异?
问题原理说明
核心差异点
setTimeout的第一个参数要求传入待延迟执行的函数引用,而IIFE(立即执行函数表达式)的本质是「定义即立即执行的函数」,这是两者出现运行差异的根本原因。
正常版本的执行逻辑
你第一个版本的代码,给setTimeout传入的是匿名函数的引用:
let count = 0 function timerFunction(miliseconds) { setTimeout(function() { console.log('This is iteration number: ' + ++count + ' and it took this many miliseconds to do the iteration:' + miliseconds) timerFunction(miliseconds) }, miliseconds) } timerFunction(2000)
执行流程完全符合预期:
- 调用
timerFunction时,仅把匿名函数本身传给setTimeout注册,没有立刻执行内部逻辑 - 等待指定毫秒数后,才会触发执行函数内的打印、递归调用逻辑
- 每次递归都有对应延迟,不会出现无限同步递归的问题
IIFE版本的执行逻辑
第二个版本中,你传给setTimeout的是IIFE的执行结果,而非待延迟的函数:
let count = 0 function timerFunction(miliseconds) { setTimeout((function() { console.log('This is iteration number: ' + ++count + ' and it took this many miliseconds to do the iteration:' + miliseconds) timerFunction(miliseconds) })(), miliseconds) } timerFunction(2000)
运行时会进入完全错误的执行流程:
- 调用
timerFunction时,JS引擎会先执行作为参数的IIFE,立刻运行内部的打印、递归调用timerFunction逻辑,根本不会等待超时 - 该IIFE没有返回值,相当于给
setTimeout传了undefined,你设置的超时参数完全无效 - 整个过程没有任何等待,直接进入无限同步递归,调用栈被快速占满,最终抛出栈溢出错误
拓展:如果需要用IIFE的正确写法
如果确实需要用到IIFE做一些初始化逻辑,可以让IIFE返回待延迟执行的函数引用即可:
setTimeout((function() { // 此处可写需要立刻执行的初始化逻辑 return function() { // 要延迟执行的逻辑放在返回的函数内 console.log('This is iteration number: ' + ++count + ' and it took this many miliseconds to do the iteration:' + miliseconds) timerFunction(miliseconds) } })(), miliseconds)
内容的提问来源于stack exchange,提问作者Jim Jay
相关产品推荐
相关产品推荐

