---
title: '优化 & 最佳实践'
sidebar_label: Optimizations
description: '让您的应用程序获得最佳性能'
---

## 使用智能指针

**注意：如果您对本节中使用的某些术语感到困惑，Rust 手册中有一个有用的[关于智能指针的章节](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)。**

为了避免在重新渲染时克隆大量数据以创建 props，我们可以使用智能指针，只克隆对数据的引用而不是数据本身。如果您在 props 和子组件中传递与相关数据的引用而不是实际数据，您可以避免在需要修改数据的子组件中克隆任何数据，您可以使用 `Rc::make_mut` 来克隆并获得要更改的数据的可变引用。

这在 `Component::changed` 中带来了更多好处，可以确定 prop 更改是否需要组件重新渲染。这是因为可以比较指针地址（即数据存储在机器内存中的位置）而不是数据的值；如果两个指针指向相同的数据，则它们指向的数据的值必须相同。请注意，反之可能不成立！即使两个指针地址不同，底层数据仍可能相同 - 在这种情况下，您应该比较底层数据。

要进行此比较，您需要使用 `Rc::ptr_eq` 而不仅仅使用 `PartialEq`（在使用相等运算符 `==` 比较数据时自动使用）。Rust 文档有关于 `Rc::ptr_eq` 的[更多细节](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.ptr_eq)。

这种优化对于不实现 `Copy` 的数据类型最有用。如果您可以廉价地复制数据，则没有必要将其放在智能指针后面。对于可能是数据密集型的结构，如 `Vec`、`HashMap` 和 `String`，使用智能指针可能会带来性能改进。

如果值从不被子组件更新，则此优化效果最佳，如果父组件很少更新，则效果更佳。这使得 `Rc<_>` 是在纯组件中包装属性值的一个不错的选择。

但是，必须注意，除非您需要在子组件中自己克隆数据，否则这种优化不仅是无用的，而且还增加了不必要的引用计数成本。Yew 中的 props 已经是引用计数的，内部不会发生数据克隆。

## 渲染函数

出于代码可读性的原因，将 `html!` 的部分重复代码迁移到专门分割出来的函数中通常是有意义的。这不仅使您的代码更易读，减少了代码缩进，而且还鼓励良好的设计模式——特别是围绕构建可组合应用程序，这些函数可以在多个地方调用，从而减少代码量。

## 纯组件

纯组件是不会改变其状态的组件，只显示内容并将消息传播到普通的可变组件。它们与视图函数的不同之处在于，它们可以在 `html!` 宏中使用组件语法（`<SomePureComponent />`）而不是表达式语法（`{some_view_function()}`），并且根据其实现，它们可以被记忆化（这意味着一旦调用函数，其值就会被“保存”，因此如果多次使用相同的参数调用它，则不必重新计算其值，只需从第一个函数调用返回保存的值）- 防止相同的 props 重新渲染。Yew 在内部比较 props，因此仅在 props 更改时重新渲染 UI。

## 使用工作区减少编译时间

Yew 的最大缺点是编译所需的时间很长。编译项目所需的时间似乎与传递给 `html!` 宏的代码数量有关。对于较小的项目，这似乎不是什么问题，但对于较大的应用程序，将代码拆分到多个 crate 中以最小化编译器为应用程序所做的工作量是有意义的。

一种可能的方法是使您的主 crate 处理路由/页面选择，然后为每个页面创建一个不同的 crate，其中每个页面可以是不同的组件或只是生成 `Html` 的大函数。存储在包含应用程序不同部分的 crate 之间的代码可以存储在项目依赖的单独 crate 中。在最理想的情况下，您从在每次编译时重新构建所有代码到仅重新构建主 crate 和一个页面 crate。在最坏的情况下，如果您在“common” crate 中编辑了某些内容，您将回到起点：编译依赖于该常用共享 crate 的所有代码，这可能是其他所有内容。

如果您的主 crate 太重，或者您想快速迭代一个深度嵌套的页面（例如。在另一个页面上渲染的页面），您可以使用示例 crate 创建主页面的简化实现，并额外渲染您正在处理的组件。

## 减小二进制文件大小

- 优化 Rust 代码
- `cargo.toml`（定义发布配置文件）
- 使用 `wasm-opt` 优化 wasm 代码

**注意：有关减小二进制文件大小的更多信息，请参阅[Rust Wasm 手册](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)。**

### Cargo.toml

可以使用 `Cargo.toml` 中 `[profile.release]` 部分中的可用设置来配置发布构建为更小。

```toml, title=Cargo.toml
[profile.release]
# 让二进制文件尺寸更小些
panic = 'abort'
# 优化整个代码库（优化更好，但构建速度也会更慢）
codegen-units = 1
# 优化尺寸（更激进的做法）
opt-level = 'z'
# 优化尺寸
# opt-level = 's'
# 使用程序整体分析时进行链接时优化
lto = true
```

### 开发版 Cargo 配置

您还可以从 Rust 和 cargo 的实验性开发版功能中获得额外的好处。要使用 `trunk` 的开发版工具链，请设置 `RUSTUP_TOOLCHAIN="nightly"` 环境变量。然后，您可以在 `.cargo/config.toml` 中配置不稳定的 rustc 功能。请参考[不稳定功能]的文档，特别是关于[`build-std`]和[`build-std-features`]的部分，以了解配置。

```toml, title=".cargo/config.toml"
[unstable]
# 需要 rust-src 组件。`rustup +nightly component add rust-src`
build-std = ["std", "panic_abort"]
build-std-features = ["panic_immediate_abort"]
```

[不稳定特性列表]: https://doc.rust-lang.org/cargo/reference/unstable.html
[`build-std`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std
[`build-std-features`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std-features

:::caution
开发版 Rust 编译器可能包含错误，例如[这个例子](https://github.com/yewstack/yew/issues/2696)，需要偶尔关注和调整。请谨慎使用这些实验性选项。
:::

### wasm-opt

此外，可以优化 `wasm` 代码的大小。

Rust Wasm 手册中有关于减小 Wasm 二进制文件大小的部分：[缩小 .wasm 大小](https://rustwasm.github.io/book/game-of-life/code-size.html)

- 使用 `wasm-pack`，默认情况下会优化发布构建中的 `wasm` 代码
- 直接在 `wasm` 文件上使用 `wasm-opt`

```text
wasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm
```

#### 在 yew/examples/ 中 'minimal' 示例的构建大小

注意：`wasm-pack` 结合了 Rust 和 Wasm 代码的优化。在此示例中，`wasm-bindgen` 未经任何 Rust 大小优化。

| 工具链                      | 大小  |
| :-------------------------- | :---- |
| wasm-bindgen                | 158KB |
| wasm-bindgen + wasm-opt -Os | 116KB |
| wasm-pack                   | 99 KB |

## 进一步阅读

- [Rust 手册中关于智能指针的章节](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)
- [Rust Wasm 手册中关于减小二进制文件大小的信息](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)
- [Rust 配置文件的文档](https://doc.rust-lang.org/cargo/reference/profiles.html)
- [binaryen 项目](https://github.com/WebAssembly/binaryen)
