首页 > 解决方案 > 为什么 ComponentDidMount 中的异步工作在导航时会导致视觉滞后,除非等待简单的 timeOut?

问题描述

我有一个选项卡式反应原生应用程序并有 2 个相关问题:

  1. 为什么在目标视图的componentDidMount方法中进行异步工作(例如发送网络请求)时,屏幕之间的导航视觉上会滞后?官方文档提到此方法是处理网络请求的适当位置,但即使componentDidMount它调用的函数被声明为 async () => 启动导航时的视觉延迟也是明显的。这种视觉延迟发生在导航开始时,在目标组件被推送或聚焦之前,即使异步工作没有以任何会影响目标组件呈现的方式修改应用程序状态,也会发生这种延迟。

  2. 为什么当我在进行真正的异步工作之前等待短暂的超时时,这种视觉延迟会完全消失?

const timeOut = t => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(`Completed in ${t}`);
    }, t);
  });
};

componentDidMount = async () => { // async or not, delay occurs
  await timeOut(0); //This line prevents navigation lag
  NetworkRequest.getData(payload);
}
...

static getData = payload => {
fetch("API_ENDPOINT", {
      method: "POST",
      body: payload
    })
      .then(response => response.json())
      .then(response => {
              //process response 
       })
}

无论是否NetworkRequest.getData等待,导航延迟都存在,而无需事先等待这个人为的迷你承诺。我觉得我误解了反应原生生命周期或渲染过程的其他一些关键部分,因为我无法想象为什么这个小小的等待对于“欺骗”该方法成为视觉异步是必要的......

编辑:既然我对消息队列和作业队列有了更多的了解,那么视觉滞后的潜在来源可能来自于用大型任务堵塞作业队列是有道理的。通过在方法中等待 timeOut async,该方法实际上成为作业队列中最低优先级的实体。似乎奇怪的屏幕转换将是非阻塞的,因为在此期间 UI 不可用,但我确信 react 原生开发人员有一个原因......文档建议在此方法中执行异步工作似乎也很奇怪如果没有此队列降级巫毒,它将阻塞...除了简单的异步之外,还有更好的方法来指定 Javascript 方法的消息/作业队列优先级吗?或者正在等待空的 timeOuts 是指示最低优先级处理的唯一方法。

使用使用 react-native 0.59 的 expo sdk 34

反应导航 3.11

和反应 16.8.3

编辑:多么巧合!Dan 5 小时前刚刚宣布对 Suspense for Data Fetching 的实验性支持 :)更多在这里

标签: reactjsreact-nativeasync-awaitreact-navigationexpo

解决方案


似乎您的NetworkRequest.getData(payload)函数正在同步执行昂贵的操作。因为 JavaScript 是单线程的,所以在此函数返回之前不会发生下一个操作,这可能会导致延迟。

通过添加await timeOut(0),您不再使其同步。现在在下一个事件循环中调用它,这意味着在此之前的任何同步操作都已经完成。


推荐阅读