React组件执行重型同步函数时如何正确切换calculating状态显示加载提示
React执行重型同步计算时展示加载提示的正确方案
问题根因
- JavaScript为单线程执行模型,同一时间只能执行一个任务,UI渲染和JS执行共用同一个主线程
- Promise构造函数的回调是同步执行的,你在第一次
setState的回调中直接调用重型计算函数,会立刻阻塞主线程,浏览器没有空闲时间把calculating=true的状态更新渲染到页面 - 等重型计算执行完毕后,两次
setState的更新会被合并处理,最终只能看到计算完成后的状态,看不到中间的加载提示 - 额外注意:原代码中
React.Components为笔误,正确写法为React.Component(末尾无s)
解决方法
将重型计算的执行时机延迟到下一个宏任务队列,让浏览器先完成当前的渲染流水线,把加载提示渲染到页面后再执行计算,修改后的代码如下:
// note: this is not async function function myHeavyFunc() {...} class Foo extends React.Component { constructor(props) { super(props); this.state = {calculating: false} this.handleXX = this.handleXX.bind(this); } handleXX() { this.setState({calculating: true}, () => { // 第一次setState,标记计算开始 // 用setTimeout将计算逻辑推入宏任务队列,等待当前渲染完成后执行 setTimeout(() => { const x = myHeavyFunc(); this.setState({calculating: false}); // 计算完成,更新状态 }, 0); }); } render() { const y = this.state.calculating? <p>calculating...</p> : ''; return ( <div> {y} <button onClick={this.handleXX}>start calc</button> </div> ); } }
优化建议
如果你的计算任务耗时极长(超过100ms),推荐使用Web Worker将计算放到后台独立线程执行,完全避免阻塞主线程的交互响应。
内容的提问来源于stack exchange,提问作者invalid
相关产品推荐
相关产品推荐

