【问题标题】:React component does not paint directly after returning JSXReact 组件返回 JSX 后不直接绘制
【发布时间】:2020-09-02 10:38:53
【问题描述】:

我有一个组件,它从视频流中捕获帧,然后在捕获的图像上运行 AI 模型,然后显示一些预测。

模型预测很慢。模型需要几秒钟来分析预测。同时,我希望 UI 反映软件正在忙于分析,因此我引入了一个状态变量来表明这一点。

粗略地说,这是我在效果挂钩中所做的:

useEffect(() => {
  if (captured && !analyzing && !results) {
    setAnalyzing(true)
    model.detect().then((predictions) => {
      setAnalyzing(false)
      setResults(predictions)
    })
  }
}, [ captured, analyzing, results ])

然而,我看到的是屏幕仅在模型完成后更新。

我的组件是一个函数式组件,以返回 JSX 的 return 语句结束。 所以我在 return 语句之前添加了一个 console.info 调用:

  // ...
  console.info('analyzing', analyzing)
  return (
    <div>
      <p>Analyzing: {analyzing ? 'true' : 'false'}</p>
      // ... 
    </div>
  )

这是奇怪的事情:分析开始后,我看到此消息直接出现在控制台中......但屏幕仍然没有实际更新。它显示“正在分析:错误”。然后,只有当模型准备好时,屏幕才会更新,但因为到那时analyzing 又是false,所以我从未真正看到屏幕变为那种状态。该模型需要几秒钟来进行分析,所以我有一个几秒钟的时间窗口,在其中我可以看到控制台消息盯着我说analyzing true,同时我在 HTML 中看到Analyzing: false

我也在控制台中收到此警告:

[Violation] 'message' handler took 383ms

我认为可能是相关的。

我遗漏了很多细节,因为我认为这与 atm 无关。但为了清楚起见,让我展示一下我的实际应用程序的日志记录:

right before the call, analysing= false
index.js:104 =======================================
index.js:105 Setting analyzing to true
index.js:106 about to call model.detect
index.js:107 call me crazy, but I expect the screen to update NOW
index.js:108   and not only after the promise from model.detect resolves...
index.js:109 =======================================
index.js:112 right after the call, analysing= false
react-dom.development.js:174 [Violation] 'message' handler took 383ms
index.js:128 rendering dialog open true streaming true captured true analysing true results null
index.js:151 returning JSX, analysing= true
i18next.js:22 i18next::translator: missingKey en translations Analysing.... Analysing....
i18next.js:22 i18next::translator: missingKey en translations OK OK
scheduler.development.js:154 [Violation] 'message' handler took 392ms
index.js:116 ANALYSIS COMPLETE arguments Arguments [callee: (...), Symbol(Symbol.iterator): ƒ]

如果您查看最后几行,消息returning JSX 是功能组件的返回语句之前的消息。当模型预测返回时,消息ANALYSIS COMPLETE 会在几秒钟后被记录。在那几秒钟内,我看到这条消息说analyzing= true,但我没有看到页面中反映了这一点。在 HTML 本身中,它根本不会更新,直到 ANALYSIS COMPLETE 消息在几秒钟后打印出来。

所以,我的问题:

什么会导致 React 延迟更新 HTML?我该如何调试才能找出答案? 我应该将模型解释移至网络工作者以防止屏幕冻结吗? 是否有任何已知的方法可以防止冻结并确保我的更新首先发生?

我尝试过的一件事是仅在屏幕更新后才使用setTimeout 并调用model.detect,这确实可以解决问题,但我觉得这是一个肮脏的黑客......或者这实际上是一个好方法解决这个问题? 我可以阅读的任何指向文档的指针都会有所帮助。不是在寻找明确的答案,而是寻找有关如何调查冻结来源的提示/建议。

【问题讨论】:

  • 尝试异步等待模型。它会起作用的。仅使用分析的依赖关系。检查if(!analyzing){ // your code}
  • async ... await 不只是 Promise ... then 的语法糖吗?如果您查看代码,您会发现在调用model.detect 之后,结果处理发生在then 中。更改为 async ... await 实际上不会改变任何事情。
  • 另外,console.log 语句显示我的 JSX 在 model.detect 调用完成之前已经返回了 analyzing=true 秒。所以我的代码已经完成了它的工作。它已经将 JSX 交给了 React……只是 HTML 并没有真正更新,可能是因为页面被冻结了。

标签: reactjs


【解决方案1】:

看起来model.detect() 可能阻塞了主线程,您可以通过检查您的应用在检测发生时是否响应事件来确认。

这可能是解决方案:

我是否应该将模型解释移至网络工作者以防止屏幕冻结?

【讨论】:

  • 是的,你是对的。没有发生任何事件。就像链接悬停在检测完成之前什么都不做。将代码移至网络工作者并解决了它。感谢您的回答!
  • 介意详细说明什么是“将 xxx 移至网络工作者”?
猜你喜欢
  • 2020-10-25
  • 2019-03-01
  • 1970-01-01
  • 2017-05-29
  • 1970-01-01
  • 2021-03-09
  • 2021-02-22
  • 1970-01-01
  • 2021-03-16
相关资源
最近更新 更多