Skip to content

Update translations #18

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
---
source-updated-at: '2025-05-16T04:52:11.000Z'
translation-updated-at: '2025-05-17T02:11:15.406Z'
source-updated-at: 2025-05-22T15:18:56.000Z
translation-updated-at: 2025-05-23T16:44:15.624Z
title: 如何优化图片
nav_title: 图片
description: 学习如何在 Next.js 中优化图片
related:
title: API 参考
description: 查看 Next.js Image 完整功能的 API 参考文档。
description: 查看 Next.js Image 完整功能集的 API 参考文档。
links:
- app/api-reference/components/image
---
Expand All @@ -15,8 +15,8 @@ Next.js 的 [`<Image>`](/docs/app/api-reference/components/image) 组件扩展

- **尺寸优化**:自动为不同设备提供正确尺寸的图片,并使用 WebP 等现代图片格式。
- **视觉稳定性**:在图片加载时自动防止[布局偏移 (layout shift)](https://web.dev/articles/cls)。
- **更快页面加载**:仅当图片进入视口时通过原生浏览器懒加载加载图片,并可选择模糊占位图
- **资源灵活性**:按需调整图片大小,即使是存储在远程服务器上的图片
- **更快页面加载**:仅当图片进入视口时通过原生浏览器懒加载加载图片,并支持可选的模糊占位图
- **资源灵活性**:按需调整图片尺寸,即使是远程服务器存储的图片

要开始使用 `<Image>`,请从 `next/image` 导入并在组件中渲染它。

Expand Down Expand Up @@ -90,7 +90,7 @@ export default function Page() {

## 远程图片

要使用远程图片,可以为 `src` 属性提供一个 URL 字符串。
要使用远程图片,您可以为 `src` 属性提供一个 URL 字符串。

```tsx filename="app/page.tsx" switcher
import Image from 'next/image'
Expand Down Expand Up @@ -124,10 +124,10 @@ export default function Page() {

由于 Next.js 在构建过程中无法访问远程文件,您需要手动提供 [`width`](/docs/app/api-reference/components/image#width-and-height)、[`height`](/docs/app/api-reference/components/image#width-and-height) 和可选的 [`blurDataURL`](/docs/app/api-reference/components/image#blurdataurl) 属性。`width` 和 `height` 用于推断正确的图片宽高比,避免图片加载时的布局偏移。

为了安全地允许来自远程服务器的图片,您需要在 [`next.config.js`](/docs/app/api-reference/config/next-config-js) 中定义支持的 URL 模式列表。尽可能具体以防止恶意使用。例如,以下配置仅允许来自特定 AWS S3 存储桶的图片:
为了安全地允许来自远程服务器的图片,您需要在 [`next.config.js`](/docs/app/api-reference/config/next-config-js) 中定义支持的 URL 模式列表。尽可能具体以防止恶意使用。例如,以下配置将仅允许来自特定 AWS S3 存储桶的图片:

```ts filename="next.config.ts" switcher
import { NextConfig } from 'next'
import type { NextConfig } from 'next'

const config: NextConfig = {
images: {
Expand Down Expand Up @@ -160,4 +160,4 @@ module.exports = {
],
},
}
```
```

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
source-updated-at: 2025-05-21T18:33:43.000Z
translation-updated-at: 2025-05-21T19:19:09.115Z
source-updated-at: 2025-05-22T15:18:56.000Z
translation-updated-at: 2025-05-23T16:46:50.155Z
title: 如何获取数据并实现流式传输
nav_title: 数据获取
description: 开始在您的应用中获取数据并流式传输内容。
Expand All @@ -14,20 +14,20 @@ related:
- app/api-reference/config/next-config-js/taint
---

本页将引导您了解如何在 [服务端与客户端组件](/docs/app/getting-started/server-and-client-components) 中获取数据,以及如何流式传输依赖数据的组件
本页将引导您了解如何在 [服务端与客户端组件 (Server and Client Components)](/docs/app/getting-started/server-and-client-components) 中获取数据,以及如何对依赖数据的组件进行 [流式传输 (streaming)](#streaming)

## 数据获取

### 服务端组件

您可以在服务端组件中通过以下方式获取数据
您可以通过以下方式在服务端组件中获取数据

1. 使用 [`fetch` API](#with-the-fetch-api)
2. 使用 [ORM 或数据库](#with-an-orm-or-database)

#### 使用 `fetch` API

要通过 `fetch` API 获取数据,将您的组件转换为异步函数,并 await `fetch` 调用。例如:
要通过 `fetch` API 获取数据,请将组件转换为异步函数,并等待 `fetch` 调用完成。例如:

```tsx filename="app/blog/page.tsx" switcher
export default async function Page() {
Expand Down Expand Up @@ -59,12 +59,12 @@ export default async function Page() {

> **须知:**
>
> - `fetch` 响应默认不会被缓存。但 Next.js 会对路由进行 [预渲染](/docs/app/getting-started/partial-prerendering#static-rendering),输出结果会被缓存以提升性能。如需启用 [动态渲染](/docs/app/getting-started/partial-prerendering#dynamic-rendering),请使用 `{ cache: 'no-store' }` 选项。参阅 [`fetch` API 参考](/docs/app/api-reference/functions/fetch)。
> - 开发环境下,您可以记录 `fetch` 调用以便更好地调试和观察。参阅 [`logging` API 参考](/docs/app/api-reference/config/next-config-js/logging)。
> - `fetch` 响应默认不会被缓存。但 Next.js [预渲染 (prerender)](/docs/app/getting-started/partial-prerendering#static-rendering) 路由,其输出会被缓存以提高性能。如需启用 [动态渲染 (dynamic rendering)](/docs/app/getting-started/partial-prerendering#dynamic-rendering),请使用 `{ cache: 'no-store' }` 选项。详见 [`fetch` API 参考](/docs/app/api-reference/functions/fetch)。
> - 开发环境下,您可以记录 `fetch` 调用以便更好地调试和观察。参见 [`logging` API 参考](/docs/app/api-reference/config/next-config-js/logging)。

#### 使用 ORM 或数据库

由于服务端组件在服务器端渲染,您可以安全地使用 ORM 或数据库客户端进行查询。将组件转换为异步函数,并 await 调用
由于服务端组件在服务器端渲染,您可以安全地使用 ORM 或数据库客户端进行查询。将组件转换为异步函数并等待调用完成

```tsx filename="app/blog/page.tsx" switcher
import { db, posts } from '@/lib/db'
Expand Down Expand Up @@ -98,21 +98,21 @@ export default async function Page() {

### 客户端组件

在客户端组件中有两种获取数据的方式
在客户端组件中获取数据有两种方式

1. 使用 React 的 [`use` 钩子](https://react.dev/reference/react/use)
1. 使用 React 的 [`use` hook](https://react.dev/reference/react/use)
2. 使用社区库如 [SWR](https://swr.vercel.app/) 或 [React Query](https://tanstack.com/query/latest)

#### 使用 `use` 钩子流式传输数据
#### 使用 `use` hook 流式传输数据

您可以使用 React 的 [`use` 钩子](https://react.dev/reference/react/use) 将数据从服务器 [流式传输](#streaming) 到客户端。首先在服务端组件中获取数据,然后将 Promise 作为 prop 传递给客户端组件:
您可以使用 React 的 [`use` hook](https://react.dev/reference/react/use) 将数据从服务器 [流式传输 (streaming)](#streaming) 到客户端。首先在服务端组件中获取数据,然后将 Promise 作为 prop 传递给客户端组件:

```tsx filename="app/blog/page.tsx" switcher
import Posts from '@/app/ui/posts
import { Suspense } from 'react'

export default function Page() {
// 不要 await 数据获取函数
// 不要等待数据获取函数
const posts = getPosts()

return (
Expand All @@ -128,7 +128,7 @@ import Posts from '@/app/ui/posts
import { Suspense } from 'react'

export default function Page() {
// 不要 await 数据获取函数
// 不要等待数据获取函数
const posts = getPosts()

return (
Expand All @@ -139,7 +139,7 @@ export default function Page() {
}
```

然后在客户端组件中使用 `use` 钩子读取 Promise:
然后在客户端组件中使用 `use` hook 读取 Promise:

```tsx filename="app/ui/posts.tsx" switcher
'use client'
Expand Down Expand Up @@ -179,7 +179,7 @@ export default function Posts({ posts }) {
}
```

在上例中,您需要用 [`<Suspense>` 边界](https://react.dev/reference/react/Suspense) 包裹 `<Posts />` 组件。这意味着在 Promise 解析期间会显示 fallback UI。了解更多关于 [流式传输](#streaming) 的内容
在上例中,`<Posts>` 组件被包裹在 [`<Suspense>` 边界](https://react.dev/reference/react/Suspense) 。这意味着在 Promise 解析期间会显示 fallback 内容。了解更多关于 [流式传输 (streaming)](#streaming) 的信息

#### 社区库

Expand Down Expand Up @@ -240,12 +240,12 @@ export default function BlogPage() {

> **警告:** 以下内容假设您的应用已启用 [`dynamicIO` 配置选项](/docs/app/api-reference/config/next-config-js/dynamicIO)。该标志在 Next.js 15 canary 版本中引入。

在服务端组件中使用 `async/await` 时,Next.js 会启用 **动态渲染**。这意味着数据将在每次用户请求时在服务器端获取并渲染。如果有任何慢速数据请求,整个路由的渲染都会被阻塞
在服务端组件中使用 `async/await` 时,Next.js 会启用 [动态渲染 (dynamic rendering)](/docs/app/getting-started/partial-prerendering#dynamic-rendering)。这意味着数据将在服务器端为每个用户请求获取并渲染。如果有任何慢速数据请求,整个路由的渲染将被阻塞

为了改善初始加载时间和用户体验,您可以使用流式传输将页面的 HTML 拆分为小块,并逐步从服务器发送到客户端
为了改善初始加载时间和用户体验,您可以使用流式传输将页面的 HTML 拆分为较小的块,并逐步将这些块从服务器发送到客户端

<Image
alt="服务端渲染与流式传输工作原理"
alt="服务端渲染与流式传输的工作原理"
srcLight="/docs/light/server-rendering-with-streaming.png"
srcDark="/docs/dark/server-rendering-with-streaming.png"
width="1600"
Expand All @@ -254,12 +254,12 @@ export default function BlogPage() {

有两种方式可以在应用中实现流式传输:

1. 使用 [`loading.js` 文件](#with-loadingjs)
2. 使用 React 的 [`<Suspense>` 组件](#with-suspense)
1. 使用 [`loading.js` 文件](#with-loadingjs) 包裹页面
2. 使用 [`<Suspense>`](#with-suspense) 包裹组件

### 使用 `loading.js`

您可以在页面所在文件夹中创建 `loading.js` 文件,在数据获取期间流式传输 **整个页面**。例如要为 `app/blog/page.js` 添加流式传输,请在 `app/blog` 文件夹中添加该文件。
您可以在页面所在文件夹中创建 `loading.js` 文件,在数据获取期间流式传输 **整个页面**。例如,要流式传输 `app/blog/page.js`,请在 `app/blog` 文件夹中添加该文件。

<Image
alt="包含 loading.js 文件的博客文件夹结构"
Expand All @@ -271,22 +271,22 @@ export default function BlogPage() {

```tsx filename="app/blog/loading.tsx" switcher
export default function Loading() {
// 在此定义加载 UI
// 在此定义加载状态 UI
return <div>Loading...</div>
}
```

```jsx filename="app/blog/loading.js" switcher
export default function Loading() {
// 在此定义加载 UI
// 在此定义加载状态 UI
return <div>Loading...</div>
}
```

导航时,用户会立即看到布局和 [加载状态](#creating-meaningful-loading-states),同时页面正在渲染。渲染完成后,新内容会自动替换显示。

<Image
alt="加载 UI"
alt="加载状态 UI"
srcLight="/docs/light/loading-ui.png"
srcDark="/docs/dark/loading-ui.png"
width="1600"
Expand Down Expand Up @@ -323,7 +323,7 @@ export default function BlogPage() {
<p>阅读以下最新文章。</p>
</header>
<main>
{/* 任何包裹在 <Suspense> 边界内的内容都会流式传输 */}
{/* 任何包裹在 <Suspense> 边界内的内容都将被流式传输 */}
<Suspense fallback={<BlogListSkeleton />}>
<BlogList />
</Suspense>
Expand All @@ -347,7 +347,7 @@ export default function BlogPage() {
<p>阅读以下最新文章。</p>
</header>
<main>
{/* 任何包裹在 <Suspense> 边界内的内容都会流式传输 */}
{/* 任何包裹在 <Suspense> 边界内的内容都将被流式传输 */}
<Suspense fallback={<BlogListSkeleton />}>
<BlogList />
</Suspense>
Expand All @@ -359,15 +359,15 @@ export default function BlogPage() {

### 创建有意义的加载状态

即时加载状态是导航后立即向用户显示的 fallback UI。为了最佳用户体验,我们建议设计有意义的加载状态,帮助用户理解应用正在响应。例如可以使用骨架屏和加载动画,或未来屏幕中的一小部分有意义内容如封面图片、标题等。
即时加载状态是导航后立即向用户显示的 fallback UI。为了最佳用户体验,我们建议设计能帮助用户理解应用正在响应的有意义加载状态。例如,可以使用骨架屏和旋转器,或未来屏幕的一小部分有意义内容如封面图片、标题等。

开发时,您可以使用 [React Devtools](https://react.dev/learn/react-developer-tools) 预览和检查组件的加载状态。

## 示例

### 顺序数据获取

顺序数据获取发生在树形结构的嵌套组件各自获取数据且请求未被 [去重](/docs/app/deep-dive/caching#request-memoization) 时,会导致响应时间变长
当树中的嵌套组件各自获取数据且请求未被 [去重 (deduplicated)](/docs/app/deep-dive/caching#request-memoization) 时,会发生顺序数据获取,导致响应时间延长

<Image
alt="顺序与并行数据获取"
Expand All @@ -377,7 +377,7 @@ export default function BlogPage() {
height="525"
/>

有时您可能需要这种模式,因为某个获取依赖于另一个获取的结果
某些情况下您可能需要这种模式,因为一次获取依赖于另一次的结果

例如,`<Playlists>` 组件只有在 `<Artist>` 组件完成数据获取后才会开始获取数据,因为 `<Playlists>` 依赖 `artistID` prop:

Expand Down Expand Up @@ -449,29 +449,29 @@ async function Playlists({ artistID }) {
}
```

为了改善用户体验,您应该使用 [React `<Suspense>`](/docs/app/building-your-application/routing/loading-ui-and-streaming#streaming-with-suspense) 在数据获取时显示 `fallback`。这将启用 [流式传输](#streaming) 并防止整个路由被顺序数据请求阻塞。
为了改善用户体验,您应该使用 [React `<Suspense>`](/docs/app/building-your-application/routing/loading-ui-and-streaming#streaming-with-suspense) 在数据获取期间显示 `fallback`。这将启用 [流式传输 (streaming)](#streaming) 并防止整个路由被顺序数据请求阻塞。

### 并行数据获取

当路由中的数据请求被主动发起并同时开始时,就会发生并行数据获取。

默认情况下,[布局和页面](/docs/app/getting-started/layouts-and-pages)是并行渲染的。因此每个路由段会尽可能早地开始获取数据
默认情况下,[布局和页面](/docs/app/getting-started/layouts-and-pages)是并行渲染的。因此每个路由段都会尽可能早地开始获取数据

然而,在_任何_组件内部,如果将多个 `async`/`await` 请求按顺序放置,它们仍然会串行执行。例如,`getAlbums` 会阻塞直到 `getArtist` 完成解析
然而,在_任何_组件内部,如果将多个 `async`/`await` 请求顺序排列,它们仍会按顺序执行。例如,`getAlbums` 将一直阻塞,直到 `getArtist` 解析完成

```tsx filename="app/artist/[username]/page.tsx" switcher
import { getArtist, getAlbums } from '@/app/lib/data'

export default async function Page({ params }) {
// 这些请求将串行执行
// 这些请求将按顺序执行
const { username } = await params
const artist = await getArtist(username)
const albums = await getAlbums(username)
return <div>{artist.name}</div>
}
```

你可以通过在数据使用组件外部定义请求,并使用 [`Promise.all`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all) 一起解析它们来实现并行请求
你可以通过在数据使用组件之外定义请求,并使用 [`Promise.all`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all) 一起解析它们来并行发起请求

```tsx filename="app/artist/[username]/page.tsx" highlight={3,8,23} switcher
import Albums from './albums'
Expand Down Expand Up @@ -537,13 +537,13 @@ export default async function Page({ params }) {
}
```

> **须知:** 使用 `Promise.all` 时,如果其中一个请求失败,整个操作都会失败。要处理这种情况,可以使用 [`Promise.allSettled`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled) 方法替代。
> **须知:** 使用 `Promise.all` 时,如果其中一个请求失败,整个操作都会失败。为了处理这种情况,可以使用 [`Promise.allSettled`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled) 方法替代。

### 数据预加载
### 预加载数据

你可以通过创建一个工具函数,在阻塞请求之前主动调用来预加载数据。`<Item>` 组件会根据 `checkIsAvailable()` 函数的返回值条件渲染
你可以通过创建一个工具函数来预加载数据,并在阻塞请求之前主动调用它。`<Item>` 会根据 `checkIsAvailable()` 函数的结果条件性渲染

你可以在 `checkIsAvailable()` 之前调用 `preload()` 来主动初始化 `<Item/>` 的数据依赖。当 `<Item/>` 渲染时,其数据已经获取完成。
你可以在 `checkIsAvailable()` 之前调用 `preload()` 来主动发起 `<Item/>` 的数据依赖请求。当 `<Item/>` 渲染时,其数据已经获取完成。

```tsx filename="app/item/[id]/page.tsx" switcher
import { getItem } from '@/lib/data'
Expand All @@ -563,7 +563,7 @@ export default async function Page({
}

export const preload = (id: string) => {
// void 会执行给定表达式并返回 undefined
// void 运算符会执行给定表达式并返回 undefined
// https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/void
void getItem(id)
}
Expand All @@ -587,7 +587,7 @@ export default async function Page({ params }) {
}

export const preload = (id) => {
// void 会执行给定表达式并返回 undefined
// void 运算符会执行给定表达式并返回 undefined
// https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/void
void getItem(id)
}
Expand Down
Loading