首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在‘ComponentDidUpdate’中有一个长时间运行的函数时,function不会在‘`render`’期间更新DOM

在‘ComponentDidUpdate’中有一个长时间运行的函数时,function不会在‘`render`’期间更新DOM
EN

Stack Overflow用户
提问于 2020-06-12 23:58:04
回答 1查看 118关注 0票数 1

我有以下情况,在我的棋盘游戏界面的基础上的反应。

我有一个事件处理程序,它在玩家移动时更新状态:

代码语言:javascript
复制
const move = ...
this.setState(function (state, _props) {
   return this.apply_move(state, move);
});

apply_move(state, move) {
   let board_copy = _.cloneDeep(state.board);
   // applies the move to board_copy somehow
   ...
   return {
     board: board_copy,
   };
}

然后我想先渲染我的移动,然后运行AI为机器人生成一个移动:这个函数调用需要几秒钟,而AI正在计算它的移动。它实际上是调用一个WebAssembly函数。

我把AI移动的请求放在componentDidUpdate

代码语言:javascript
复制
componentDidUpdate(prevProps, prevState) {
    if (this.state.history.length > prevState.history.length) {
      if (this.botHasToMove()) {
        this.getMoveFromBot();   // <--- this runs for 5 seconds
      }
    }
}

我预计这将在调用render之后运行,所以我将首先看到我的移动呈现,然后在AI计算时暂停几秒钟,然后应该呈现AI移动。

然而,问题是,即使在请求AI移动之前,我在控制台中看到了render的调用,而且我可以看到状态是用我的移动更新的,但是DOM本身并没有被更新。只有当获得AI移动的长调用完成并再次发生render时,它才会被更新。然后,两个动作同时呈现,我可以在浏览器中看到它们。

我希望每个对render的调用都应该更新DOM (如果发生了一些变化,在我的例子中),但是由于某种原因,DOM更新没有发生。

如果我不调用componentDidUpdate中对AI的长调用,一切正常,我可以看到第一个render的效果。

请有人解释一下为什么会发生这种情况,并告诉我在第一个render调用中强制更新DOM的正确方法是什么?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-06-13 01:09:25

我喜欢你提出的问题,因为我喜欢这类问题,你的代码实际上做得很好,但是你的代码有问题,你实际上提到了一个长调用或长执行代码,JS运行在一个线程中,这意味着所有进程都运行在一个通道(线程),所以我强烈建议您观看这两个视频,关于JS中的事件循环,这是您出现问题的原因:

如何工作事件循环JS - JSConf.Asia

如何工作事件循环JS - JSConf EU

简单地说,您的问题是在JS中阻塞线程执行,我的意思是所有的JS执行都是在一个“执行队列”中顺序执行的,所以下一个执行代码在前面的代码完成之前不会执行。

那你怎么解决这个问题呢?为了避免阻塞线程,您需要在另一个线程中执行代码,但是JS只是一个线程执行语言,所以您确实需要一些名为WebWorkers的东西,它们允许您在另一个“线程”中运行代码,因此您的问题是阻塞执行队列,因为执行函数花费的时间太长,无法解决。

我希望这能对您有很大帮助,并帮助您了解JS事件循环/执行队列的工作原理。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62354011

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档