我在考虑博客首页优化的时候,灵机一动想要先响应前 10 条博客,然后流式响应剩下的。就问了一下 gpt 。除了第一问以外,后续都是在跟 gpt 争论。。。
我认为在博文只有 100 条左右的时候,/api/posts
应该没有明显差距(尤其是 posts 接口还不获取内容,只获取标题、简介、发布日期之类的东西)
我假设都需要 200ms.
那么按 gpt 的意思来干的话,页面会是
|-- 白屏
|--|-- 200ms 后接口获取到数据,渲染 html 输出到前端
|--|-- 同时 Suspense 显示 fallback
|--|-- 同时请求第二个 get 接口,
|--|--|-- 再 200ms 后接口获取到数据,渲染 html 输出到前端
按我的意思的话,页面会是
|-- Suspense 立即显示 fallback
|-- 同时请求 get 接口,
|--|-- 200ms 后接口获取到数据,渲染 html 输出到前端
这不是明显我的方案更优吗,省了 200ms 的白屏。可 gpt 非说它的更好。
大佬们帮我看看,是不是我理解得不到位。
'use server'
async function Posts({ start, count }: { start: number; count?: number }) {
const data = await get('/api/posts', {
start,
// 假设 count 为空的时候获取后续所有
count,
})
return <RenderPosts data={data} />
}
// gpt 的意思是这样
export function Page() {
return <>
<Posts start={0} count={10} />
<Suspense fallback={<div>loading</div>}>
<Posts start={10} />
</Suspense>
</>
}
// 我的意思是这样
export function Page() {
return <>
<Suspense fallback={<div>loading</div>}>
<Posts start={0} />
</Suspense>
</>
}
1
2020583117 14 天前
然后等 AllPosts 完全 resolve (也就是所有 100 篇数据都 fetch 完成并渲染完)。
我的理解不就是先渲染 10 条能早点看见内容吗?然后请求 100 条的时间会更长(因为响应时间更长) |
![]() |
2
xiaoming1992 OP |
3
jlak 14 天前 via iPhone
gpt 可能假设你 page.js 之前还有一层 loading.js
|
![]() |
4
xiaoming1992 OP @jlak 我已经把我的伪代码给他了,就是提问中末尾那段
|
5
renmu123 14 天前
如果你重视 首屏体验(首屏是指用户真正看到有意义的内容)
|
![]() |
6
xiaoming1992 OP @renmu123 问题是按照 gpt 说的,前 200ms 是白屏啊,我不过是把白屏的时间换成 loading 罢了(应该是这样吧?)
|
![]() |
7
SanjinGG 14 天前 via Android
Gpt 只是 posts count10 不在 suspense 里,不然白屏也是 loading ,gpt 的方案应该是先请求 10 条,这样是可以更快看到内容的,后续的 post 应该是滚动加载的,但 gpt 直接一次性请求了,正常应该是 gpt 体验更好,但现在的网速,这么少量的数据差距不是很大
|
![]() |
8
zizon 13 天前
> 假设都需要 200ms.
gpt 把这个丢了吧. 认为两类请求代价不同. |
![]() |
9
xiaoming1992 OP @zizon 我没太理解,不都是在服务端发的请求吗?
|
10
rocmax 10 天前 via Android
suspense 标签内的组件需要支持流式传输,你可以用 use hook 或者 react query 和 useSuspenseQuery 来实现,表明不用等待 suspense 内部的处理,其他内容渲染完就可以发送。
你现在的实现在服务器端等待从 API 获取数据然后渲染,这种情况下 suspense 没有意义,你直接渲染全部然后发送就完了。 如果希望 suspense 有效,个人推荐的方式是在服务器组件中 prefetch ,然后添加 hydration boundary ,在 suspense 内的组件中使用 usesuspensequery 。 如果想精确实现你的需求,那么在服务器组件中 await 获取前 10 条,然后用 react query 发起另一个 prefetch 请求获取后面的但不要 await ,最后在 suspense 内部使用 usesuspensequery 。这样很麻烦没太大意义。如果条目多不如考虑 react query 的 infiniteQuery 实现滚动加载。 |