優化與最佳實例
neq_assign
當元件從父元件接收到屬性時, change
的方法就會被呼叫。除了讓你更新元件的狀態,也讓你回傳,決定元件是否要在屬性改變時,重新渲染自己的布林值 ShouldRender
。
重新渲染是很浪費效能的,儘可能避免這麼做。一般來說,只有在屬性真的改變時,才重新渲染。下面的程式碼是體現這個原則的例子,當屬性改變時,才回傳 true
:
use yew::ShouldRender;
#[derive(PartialEq)]
struct ExampleProps;
struct Example {
props: ExampleProps,
};
impl Example {
fn change(&mut self, props: ExampleProps) -> ShouldRender {
if self.props != props {
self.props = props;
true
} else {
false
}
}
}
但我們可以走的更遠!這六行的模板,使用一個 trait 和一個 實作了 PartialEq
的 blanket implementation ,可以被縮短至一行。請參考這裡, yewtil
的 crate 裡的 NeqAssign
trait。
RC
為了避免重新渲染時,複製大量的資料來建立屬性,我們可以使用智慧指針來讓程式只複製指針。如果你使用 Rc<_>
來封裝你的屬性,而不是未封裝的值,你可以使用 Rc::make_mut
,去複製與存取你想要改變的資料的可變參考,這做到了延遲複製,直到你需要更動子元件的資料。透過避免複製直到有值改變,子元件可以在 Component::change
拒絕與他狀態中的屬性相同值的屬性,而且這樣不會有任何效能成本。另外,這個方式,資料必須在與子元件比較與被拒絕之前,被複製進父元件的屬性中。
這個優化最那些無法 Copy
的資料型別最有用。如果你可以輕易複製你的資料,那把資料放進智慧指針裡面似乎就沒有這麼值得。對於那些包含很多像是 Vec
、 HashMap
與 String
的結構,這個優化對他們會更值得。
如果子元件幾乎不會更新值,那這個優化效果會很好,甚至如果父元件也很少更新,那效果會更好。上面的情況,使在純元件中使用 Rc<_>s
是一個封裝屬性值很好的選擇。
View 方法
出於程式碼的可讀性,通常會寫方法包裝複雜的 html!
,這樣你可以避免巢狀的 HTML 造成過多的向右縮排。
純元件/函數式元件
純元件 是一種不會改變自己狀態的元件,他們只單純顯示內容或是向普通可變的元件傳送訊息。他們和 view 方法不同的地方在於們可以在 html!
巨集中使用,語法會像(<SomePureComponent />
),而不是表達式語法({some_view_function()}
),而且根據他們的實作方式,他們可以被 memoized,這樣可以套用前面所述的 neq_assign
的邏輯避免重新渲染。
Yew 本身不支援純元件或是函數式元件,但是你可以透過 external crates 使用。
函數式元件還不存在,但是理論上純元件可以透過巨集與宣告方法產生。
Keyed DOM nodes when they arrive
使用 Cargo Workspaces 加速編譯
Yew 最大的缺點就是花太多時間在編譯上了。編譯時間似乎和 html!
巨集中的程式碼質量相同。 對於小專案來說,這應該不是什麼大問題,但是對於有很多頁面的大型網頁應用程式來說,就必須要將程式碼封裝成很多 crates 以減少編譯所花的時間。
你應該將路由與頁面區塊封裝成一個 main crate,然後將共用的程式碼與元件封裝成另一個 crate,將每個頁面會用到的不同的元件,各自封裝到不同的 crate 中,或是只產生 Html
的大方法中。最好的狀況,你只需要重新編譯你 main crate 與修改的頁面的 crate 的程式碼;而最壞的情況,你編輯了共用的 crate,你就必須重新編譯所有依賴這個共用 crate 的程式碼。
如果你的 main crate 太過龐大,或是你希望快速迭代深層巢狀的頁面(一個頁面渲染另一個頁面的頂層),你可以使用範例的 crate ,在一個簡單的主頁面上編輯你未完成的元件。
編譯大小的優化
- 優化 Rust 的程式碼
wee_alloc
(使用輕量的分配器)cargo.toml
(定義釋出的設定檔)
- 使用
wasm-opt
優化 wasm 程式碼
更多關於程式碼大小的資訊,請參考: rustwasm book
wee_alloc
wee_alloc 是一個比一般用在 Rust 二進制檔中的分配器更輕量的分配器。用他取代預設的分配器,可以讓 Wasm 的檔案大小更小,但是會造成速度和記憶體的開銷變大。
但比起檔案大小,速度和記憶體的開銷比較次要。更小的檔案大小意味著你的頁面可以載入的更快,因此我們通常建議你使用這個分配器作為預設的分配器,除分你的專案有很多吃重的記憶體分配工作。
// 使用 `wee_alloc` 作為全局的分配器
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
Cargo.toml
你可以設定你的發行版本更小的檔案大小,透過設定 Cargo.toml
的 [profile.release]
。
[profile.release]
# less code to include into binary
panic = 'abort'
# optimization over all codebase ( better optimization, slower build )
codegen-units = 1
# optimization for size ( more aggresive )
opt-level = 'z'
# optimization for size
# opt-level = 's'
# link time optimization using using whole-program analysis
lto = true
wasm-opt
更多優化 wasm
程式碼大小的方法。
wasm-opt 資訊: binaryen project
Rust Wasm 中有一個關於減少 Wasm 二進位檔大小的章節:Shrinking .wasm size
- 使用
wasm-pack
預設在發行版本編譯時優化wasm
程式碼 - 直接在 wasm 檔案上使用
wasm-opt
。
wasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm
編譯 yew/examples/ 中 最小的例子
注意: wasm-pack
包含對 Rust 與 wasm 程式碼的優化。而wasm-bindgen
只是一個單純的例子,沒有對 Rust
做任何優化。
used tool | size |
---|---|
wasm-bindgen | 158KB |
wasm-binggen + wasm-opt -Os | 116KB |
wasm-pack | 99KB |