[React 19] 在react-server中,与异步操作不一致的"cache" api

wgeznvg7  于 5个月前  发布在  React
关注(0)|答案(2)|浏览(86)

描述:

在使用 node 运行提供的代码时,我遇到了一个问题,即缓存在存在异步操作时是否一致取决于情况。

重现步骤:

  1. 使用 node 运行以下代码:
const { renderToReadableStream } = require("react-server-dom-webpack/server.edge");
const { cache, createElement } = require("react");

const getId = cache(() => ({ id: Math.random() }));

const A = async () => {
    await new Promise(setImmediate);
    const id = getId();
    console.log(id);
    return null;
};

const B = async () => {
    const id = getId();
    console.log(id);
    return createElement(A, {}, null);
};

renderToReadableStream(createElement(B, {}, null), null);
  1. 观察控制台输出。在 AB 中记录的 id 值不同。
  2. A 中删除 await new Promise(setImmediate); 这一行并修改代码:
const A = async () => {
  const id = getId();
  console.log(id);
  return null;
};
  1. 再次使用 node 运行修改后的代码。
  2. 观察控制台输出。现在在 AB 中记录的 id 值是相同的。

预期行为:

无论渲染过程中是否存在异步操作, id 的值应该是一致的。

实际行为:

当渲染方法中存在异步操作时, id 的值是不同的。

重现代码:

您可以使用以下命令运行代码:

npm run start

或者在一个代码沙箱中运行:
https://codesandbox.io/p/github/nestarz/react-19-cache-issue/main?import=true
以及在 GitHub 仓库中查看:
https://github.com/nestarz/react-19-cache-issue

附加信息:

似乎在涉及渲染过程的异步操作期间存在请求上下文传播的问题。这导致了不一致的行为,可能会导致不可预测的错误。

环境:

  • node v20.8.1
{
  "name": "test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node --conditions react-server index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "react": "^19.0.0-rc-e684ca66ab-20240619",
    "react-server-dom-webpack": "^19.0.0-rc-e684ca66ab-20240619"
  }
}

它影响了异步渲染场景中的缓存一致性和可靠性,当用作服务器上下文的替代方案时,这是正常的吗?谢谢!

pxq42qpu

pxq42qpu1#

请注意,.edge 包不打算在Node.js中使用。至少不是像Next.js那样完全控制环境,但即使这样,它甚至也不建议用于Next.js。
你应该使用 react-server-dom-webpack/server (在 "node" 条件下解析为 react-server-dom-webpack/server.node )。
有很多细微的事情是依赖于环境的。例如,这个检查是一个遗留检查,它会在全局对象上查找AsyncLocalStorage,因为在某些“边缘”环境中导入它不起作用或需要一个标志。
https://github.com/facebook/react/blob/main/packages/react-server/src/forks/ReactFlightServerConfig.dom-edge.js#L17
所以你需要设置它在全局上暴露,但这实际上是我们打算在所有环境赶上来后改变的事情。
但是,由于流以及边缘使用setTimeout进行调度,还有调试信息只能通过Node.js构建获得,因此在使用Node.js中的Edge会导致性能更差。
因此,目前不支持在Node.js中使用“edge”构建。

3pmvbmvn

3pmvbmvn2#

感谢@sebmarkbage,请问在哪个环境中,边缘构建(edge build)应该如何工作?
我找到了一个简单的复现方法,但当我使用"react-server-dom-esm/server.node"时,我遇到了真正的问题。以下是CodeSandbox链接:https://codesandbox.io/p/github/nestarz/react-19-cache-issue/jsr
以及相关的构建文件:https://jsr.io/@bureaudouble/rsc-engine/0.0.101/vendor/react-server-dom-esm/cjs/react-server-dom-esm-server.node.development.js
所以,问题不是因为运行时环境,而是因为"esm"构建。我知道它也不是很受支持,但是你能告诉我一个修复方法吗?这样AsyncLocalStorage就能更好地工作了?
透露一下,我正在尝试构建一个简单的元框架,用于在Node和Deno等多种运行时环境中使用。
除了使用webpack之外,我还完全依赖于esbuild来构建客户端组件及其依赖项,并利用import-maps进行解析。
该框架运行良好;请查看这里:https://github.com/nestarz/bureaudouble-rsc-demo/
唯一缺失的部分是在渲染生命周期以及多个异步操作中保持有效的请求上下文;我相信问题出在React代码库中。

相关问题