快速重复点击按钮时,为何console.log异步执行顺序异常?
快速重复点击"CLICK ME"按钮时,为何
console.log(=${innerCount}.2);可能先于console.log(=${innerCount}.1);执行? 问题核心原因
出现执行顺序颠倒的情况,本质是lodash throttle的节流逻辑与异步函数的await行为共同作用的结果,结合两层节流的时间差(50ms vs 100ms),具体拆解如下:
lodash throttle的默认行为
lodash的throttle默认配置为{leading: true, trailing: false}:- 节流周期的首次调用会立即执行原函数;
- 节流周期内的后续调用会被直接忽略,不会执行原函数,且返回
undefined。
异步函数的await处理
await关键字如果接收到非Promise类型的值(比如undefined),会自动将其转换为已resolved的Promise,代码会立即继续执行后续逻辑。快速点击时的执行流程
假设快速点击触发两次handleClick执行:- 第一次执行(innerCount=1):
handleClick调用throttledFetchData(1),因是节流周期内首次调用,throttledFetchData的原异步函数立即执行,进入await callApi()等待接口响应,此时handleClick(1)处于等待状态,两个console.log都未执行。 - 第二次执行(innerCount=2,间隔50ms):
handleClick调用throttledFetchData(2),此时距离throttledFetchData首次调用还未到100ms节流周期,lodash忽略原函数执行,直接返回undefined。
由于await undefined会立即resolve,handleClick(2)跳过等待,直接执行console.log('===2.2')。 - 后续:
当第一次callApi()响应完成后,才会执行console.log('===1.1'),最后执行console.log('===1.2')。
这就导致了
===2.2先于===1.1出现在控制台的现象。- 第一次执行(innerCount=1):
补充说明
- 两层
throttle是失误操作,调试时触发了该执行顺序问题; - 问题仅在快速重复点击时才会复现,因为只有高频触发才会导致
handleClick在throttledFetchData的节流周期内重复调用。
现象展示


代码示例
let count = 0; const App = () => { const throttledFetchData = throttle(async (innerCount) => { const result = await callApi(); console.log(`===${innerCount}.1`); return result; }, 100); const handleClick = throttle(async (e) => { count++; const innerCount = count; const result = await throttledFetchData(innerCount); console.log(`===${innerCount}.2`); }, 50); return ( <div className='container' onClick={handleClick}> CLICK ME </div> ); }
注:代码中throttle来自lodash
内容的提问来源于stack exchange,提问作者Mia
相关产品推荐
相关产品推荐

