首页 > 解决方案 > 让 React 在长时间运行的任务之间渲染页面

问题描述

我在 Javascript 中有一个长期运行的任务。React 应该在任务之间的几个点上重新渲染组件。但它仅在整个任务结束时重新渲染。如何让 React 在所有setState()调用中重新渲染页面?

一个简化的例子:

setStatePromise = (state) => new Promise(resolve => {
    this.setState(state, () => resolve());
});
longRunningTask = async () => {
    await this.setStatePromise({progress: 1}); // not shown to the user
    await doMuchWork();
    await this.setStatePromise({progress: 2}); // not shown to the user
    await doEvenMoreWork();
    await this.setStatePromise({progress: 3}); // shown to the user when everything is done
};
onButtonClick = async () => {
    await this.longRunningTask();
}

这是一个显示问题的工作示例:

https://codesandbox.io/s/intelligent-cori-31qn5

我之前使用的解决方法是:

setStatePromise = (state) => new Promise(resolve => {
    this.setState(state, () => {
        setTimeout(() => resolve(), 1);
    });
});

标签: javascriptreactjsasync-awaites6-promise

解决方案


“渲染”方法被连续调用。问题是因为 Javascript 是单线程的。

doMuchWork 内部的循环阻塞了主线程(以及 UI)。

如何在不阻塞 UI 的 Javascript 中执行循环?

解决该问题的一种快速方法是将 doMuchWork 中的算法(如果可能的话)拆分为步骤/块:https ://codesandbox.io/embed/nostalgic-wiles-g38ce ,但它有很多缺点。

setTimeout 允许其他方法等完成他们的工作(如刷新 UI),将回调稍后放入队列中,这就是为什么本主题中给出的 setTimeout(..., 1000) 解决方案效果很好。

其他(更好的)方法是使用建议的生成器或使用专门为执行此类耗时工作而创建的 Web Worker。

关于您使用 Web Workers 的解决方案的问题


推荐阅读