偵錯

在撰寫更多程式碼之前,當事情出現問題時,我們會希望實作一些偵錯工具,以便隨時使用。花點時間檢閱列出可用於偵錯 Rust 生成的 WebAssembly 工具和方法的參考頁面

為 Panic 啟用記錄

如果我們的程式碼會 Panic,我們希望在開發人員主控台中顯示詳細的錯誤訊息。

我們的 wasm-pack-template 已附帶一個可選的、由預設啟用的相依項console_error_panic_hook 箱子,其設定在 wasm-game-of-life/src/utils.rs 內。我們只需要在初始化函式或一般程式碼路徑中安裝掛鉤。我們可以在 wasm-game-of-life/src/lib.rsUniverse::new 建構函式內呼叫它


# #![allow(unused_variables)]
#fn main() {
pub fn new() -> Universe {
    utils::set_panic_hook();

    // ...
}
#}

為我們的生命遊戲加入記錄

讓我們使用 web-sys 箱子透過 console.log 函式為 Universe::tick 函式中的每個儲存格加入一些記錄

首先,將 web-sys 加入為相依項,並在 wasm-game-of-life/Cargo.toml 中啟用其 "console" 功能

[dependencies]

# ...

[dependencies.web-sys]
version = "0.3"
features = [
  "console",
]

為符合人體工學,我們會將 console.log 函式包裝在一個類似 println! 的巨集中


# #![allow(unused_variables)]
#fn main() {
extern crate web_sys;

// A macro to provide `println!(..)`-style syntax for `console.log` logging.
macro_rules! log {
    ( $( $t:tt )* ) => {
        web_sys::console::log_1(&format!( $( $t )* ).into());
    }
}
#}

現在,我們可以通過在 Rust 程式碼中插入對 log 的呼叫來開始將訊息記錄到主控台。例如,若要記錄每個儲存格的狀態、存活鄰居的數量和下一個狀態,我們可以這樣修改 `wasm-game-of-life/src/lib.rs`

diff --git a/src/lib.rs b/src/lib.rs
index f757641..a30e107 100755
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -123,6 +122,14 @@ impl Universe {
                 let cell = self.cells[idx];
                 let live_neighbors = self.live_neighbor_count(row, col);

+                log!(
+                    "cell[{}, {}] is initially {:?} and has {} live neighbors",
+                    row,
+                    col,
+                    cell,
+                    live_neighbors
+                );
+
                 let next_cell = match (cell, live_neighbors) {
                     // Rule 1: Any live cell with fewer than two live neighbours
                     // dies, as if caused by underpopulation.
@@ -140,6 +147,8 @@ impl Universe {
                     (otherwise, _) => otherwise,
                 };

+                log!("    it becomes {:?}", next_cell);
+
                 next[idx] = next_cell;
             }
         }

使用除錯程式在每次滴答聲之間暫停

瀏覽器的逐步除錯程式對於檢查 Rust 生成的 WebAssembly 進行互動很有幫助。

例如,我們可以在 `renderLoop` 函數的每次反覆運算中使用除錯程式來暫停,方法是在我們呼叫 `universe.tick()` 的上方放置 一個 JavaScript debugger; 敘述

const renderLoop = () => {
  debugger;
  universe.tick();

  drawGrid();
  drawCells();

  requestAnimationFrame(renderLoop);
};

這為我們提供了檢查已記錄訊息和將目前呈現的畫面與前一個畫面進行比較的一個方便檢查點。

Screenshot of debugging the Game of Life

練習

  • 將記錄轉移狀態從存在轉變成不存在或相反的每個儲存格的列和行加入到 `tick` 函數。

  • 在 `Universe::new` 方法中引入一個 `panic!()`。在你的網頁瀏覽器的 JavaScript 除錯程式中檢查異常的回溯。停用除錯符號,重新建立而不使用 `console_error_panic_hook` 可選的依存性,然後再次檢查堆疊追蹤。它沒有那麼有用,對吧?