跳转到内容

使用流式处理来提升页面性能

Astro 的 SSR 使用 HTML 流式处理来在组件可用时将其发送到浏览器,以便更快地加载页面。为了进一步提升你的页面性能,你可以策略性地构建你的组件,即通过避免阻塞的数据获取来优化它们的加载速度。

如下的重构示例演示了如何通过将获取调用移动到其他组件,并将它们从阻塞页面渲染的组件中迁移出来,以提高页面性能。

以下页面在 frontmatter 中会 await 一些数据。而 Astro 会等待所有的 fetch 调用解决后,再将 HTML 发送到浏览器。

src/pages/index.astro
---
const personResponse = await fetch('https://randomuser.me/api/');
const personData = await personResponse.json();
const randomPerson = personData.results[0];
const factResponse = await fetch('https://catfact.ninja/fact');
const factData = await factResponse.json();
---
<html>
<head>
<title>A name and a fact</title>
</head>
<body>
<h2>A name</h2>
<p>{randomPerson.name.first}</p>
<h2>A fact</h2>
<p>{factData.fact}</p>
</body>
</html>

现在可将 await 调用移入粒度较小的组件可以让你充分利用 Astro 的流式处理。使用以下组件来执行数据获取,Astro 可以先渲染一些 HTML,例如标题,然后在数据准备好时渲染段落。

src/components/RandomName.astro
---
const personResponse = await fetch('https://randomuser.me/api/');
const personData = await personResponse.json();
const randomPerson = personData.results[0];
---
<p>{randomPerson.name.first}</p>
src/components/RandomFact.astro
---
const factResponse = await fetch('https://catfact.ninja/fact');
const factData = await factResponse.json();
---
<p>{factData.fact}</p>

下面的 Astro 页面使用这些组件可以更早地渲染页面的部分内容。<head><body><h1> 标签则不再被数据获取所阻塞。接着,服务器将并行获取 RandomNameRandomFact 的数据,并将生成的 HTML 流式传输到浏览器上。

src/pages/index.astro
---
import RandomName from '../components/RandomName.astro';
import RandomFact from '../components/RandomFact.astro';
---
<html>
<head>
<title>A name and a fact</title>
</head>
<body>
<h2>A name</h2>
<RandomName />
<h2>A fact</h2>
<RandomFact />
</body>
</html>

你也可以直接在模板中包含 promises。它不会阻塞整个组件,而是会并行地解决 promise,并只阻塞其后的标记。

src/pages/index.astro
---
const personPromise = fetch('https://randomuser.me/api/')
.then(response => response.json())
.then(arr => arr[0].name.first);
const factPromise = fetch('https://catfact.ninja/fact')
.then(response => response.json())
.then(factData => factData.fact);
---
<html>
<head>
<title>A name and a fact</title>
</head>
<body>
<h2>A name</h2>
<p>{personPromise}</p>
<h2>A fact</h2>
<p>{factPromise}</p>
</body>
</html>

在这个例子中,A name 会在 personPromisefactPromise 加载时渲染。一旦 personPromise 解决了,A fact 就会出现,factPromise 也将在完成加载时渲染。