如何延迟 CPU 密集任务以允许渲染发生
How to delay CPU intensive tasks to allow render to happen
我有一个 React 应用程序,其中发生了多个顺序 CPU 密集型任务。我想跟踪整体操作的进度。
class Hello extends React.Component {
constructor() {
super()
this.state = {
status: 'not started'
}
this.handler = this.handler.bind(this)
}
componentDidUpdate() {
if(this.state.status === 'starting') {
this.cpuIntensive()
this.setState({status: 'first task done'})
}
if(this.state.status === 'first task done') {
this.cpuIntensive()
this.setState({status: 'second task done'})
}
if(this.state.status === 'second task done') {
this.cpuIntensive()
this.setState({status: 'finished'})
}
}
cpuIntensive() {
let result = 0
for (var i = Math.pow(7, 8); i >= 0; i--) {
result += Math.atan(i) * Math.tan(i);
}
}
handler() {
this.setState({status: 'starting'})
}
render() {
return (
<div>
<div>{this.state.status}</div>
<button onClick={this.handler}>START</button>
</div>
)
}
}
ReactDOM.render(
<Hello name="World" />,
document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="container"></div>
在此代码段中,当您单击 START
时,状态确实会发生变化,我们会经历 componentDidUpdate
但组件不会重新呈现。
为了让它像我想要的那样工作,我可以这样做:
class Hello extends React.Component {
constructor() {
super()
this.state = {status: 'not started'}
this.handler = this.handler.bind(this)
}
componentDidUpdate() {
if(this.state.status === 'starting') {
setTimeout(() => {
this.cpuIntensive()
this.setState({status: 'first task done'})
}, 100)
}
if(this.state.status === 'first task done') {
setTimeout(() => {
this.cpuIntensive()
this.setState({status: 'second task done'})
}, 100)
}
if(this.state.status === 'second task done') {
setTimeout(() => {
this.cpuIntensive()
this.setState({status: 'finished'})
}, 100)
}
}
cpuIntensive() {
let result = 0
for (var i = Math.pow(7, 8); i >= 0; i--) {
result += Math.atan(i) * Math.tan(i);
}
}
handler() {
this.setState({status: 'starting'})
}
render() {
return (
<div>
<div>{this.state.status}</div>
<button onClick={this.handler}>START</button>
</div>
)
}
}
ReactDOM.render(
<Hello name="World" />,
document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="container"></div>
IMO 看起来很糟糕。我正在寻找替代品:)
感谢您的宝贵时间。
编辑:网络工作者不是一个选项
您可以在 handler
中开始您的操作,并使用 setTimeout()
链接/允许渲染在两者之间发生。那么你就不需要使用反应状态来启动那些连续的操作。
另一种选择是使用 WebWorker。
我有一个 React 应用程序,其中发生了多个顺序 CPU 密集型任务。我想跟踪整体操作的进度。
class Hello extends React.Component {
constructor() {
super()
this.state = {
status: 'not started'
}
this.handler = this.handler.bind(this)
}
componentDidUpdate() {
if(this.state.status === 'starting') {
this.cpuIntensive()
this.setState({status: 'first task done'})
}
if(this.state.status === 'first task done') {
this.cpuIntensive()
this.setState({status: 'second task done'})
}
if(this.state.status === 'second task done') {
this.cpuIntensive()
this.setState({status: 'finished'})
}
}
cpuIntensive() {
let result = 0
for (var i = Math.pow(7, 8); i >= 0; i--) {
result += Math.atan(i) * Math.tan(i);
}
}
handler() {
this.setState({status: 'starting'})
}
render() {
return (
<div>
<div>{this.state.status}</div>
<button onClick={this.handler}>START</button>
</div>
)
}
}
ReactDOM.render(
<Hello name="World" />,
document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="container"></div>
在此代码段中,当您单击 START
时,状态确实会发生变化,我们会经历 componentDidUpdate
但组件不会重新呈现。
为了让它像我想要的那样工作,我可以这样做:
class Hello extends React.Component {
constructor() {
super()
this.state = {status: 'not started'}
this.handler = this.handler.bind(this)
}
componentDidUpdate() {
if(this.state.status === 'starting') {
setTimeout(() => {
this.cpuIntensive()
this.setState({status: 'first task done'})
}, 100)
}
if(this.state.status === 'first task done') {
setTimeout(() => {
this.cpuIntensive()
this.setState({status: 'second task done'})
}, 100)
}
if(this.state.status === 'second task done') {
setTimeout(() => {
this.cpuIntensive()
this.setState({status: 'finished'})
}, 100)
}
}
cpuIntensive() {
let result = 0
for (var i = Math.pow(7, 8); i >= 0; i--) {
result += Math.atan(i) * Math.tan(i);
}
}
handler() {
this.setState({status: 'starting'})
}
render() {
return (
<div>
<div>{this.state.status}</div>
<button onClick={this.handler}>START</button>
</div>
)
}
}
ReactDOM.render(
<Hello name="World" />,
document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="container"></div>
IMO 看起来很糟糕。我正在寻找替代品:)
感谢您的宝贵时间。
编辑:网络工作者不是一个选项
您可以在 handler
中开始您的操作,并使用 setTimeout()
链接/允许渲染在两者之间发生。那么你就不需要使用反应状态来启动那些连续的操作。
另一种选择是使用 WebWorker。