跳转到内容

使用流式传输提升页面性能

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

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

以下页面在其 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><h2> 标签不再被数据获取阻塞。服务器将并行获取 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>

你也可以直接在模板中包含 Promise。它不会阻塞整个组件,而是会并行地解析该 Promise,并且只阻塞其后的标记(markup)。

src/pages/index.astro
---
const personPromise = fetch('https://randomuser.me/api/')
.then(response => response.json())
.then(personData => personData.results[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>

在这个例子中,当 personPromisefactPromise 正在加载时,A name 会先渲染。一旦 personPromise 解析完成,A fact 就会出现,而 factPromise 会在它加载完成后渲染。

贡献 社区 赞助