問題
↑
- この example の
runにrustwasm/wasm-bindgenのような、実装上GitHub APIで取得可能なポジトリーが実在する場合は問題ありません。 - リポジトリーが存在しないパターンを
runに与えてfetchさせるとasync/JsFuture処理系の都合か二度とrunを使用できない .wasm が生成されてしまいます。
問題は example の run の最後の2行:
// Use serde to parse the JSON into a struct. let branch_info: Branch = json.into_serde().unwrap(); // Send the `Branch` struct back to JS as an `Object`. Ok(JsValue::from_serde(&branch_info).unwrap())
解決方法
match で json の Err<serde_json::error::Error> を Err<JsValue> に射る:
// 解決方法①段階 match json.into_serde() as Result<Branch, serde_json::error::Error> { Ok(branch_info) => Ok(JsValue::from_serde(&branch_info).unwrap()), Err(e) => Err(JsValue::from_str(&format!("{}", e))), }
↑だとまだ json.into_serde() は Ok だけど JsValue::from_serde が Err だった場合は死んでしまいますが、 GitHub API は実在しないリポジトリーに対しても JSON を返してはくれるので、さしあたりは問題にはなりません。そこも match すると↓:
// 解決方法②段階 match json.into_serde() as Result<Branch, serde_json::error::Error> { Ok(branch_info) => match JsValue::from_serde(&branch_info) { Ok(jsvalue) => Ok(jsvalue), Err(e) => Err(JsValue::from_str(&format!("{}", e))), }, Err(e) => Err(JsValue::from_str(&format!("{}", e))), }
↑のそこはかとない多段 match のダサさを Result の map と map_err で整理すると:
// 解決方法③段階 (json.into_serde() as Result<Branch, serde_json::error::Error>) .map(|branch_info| JsValue::from_serde(&branch_info).unwrap()) .map_err(|e| JsValue::from_str(&format!("{}", e)))
- (1.
json.into_serde()):json.into_serde():=Ok<Branch>かErr<serde_json::error::Error>です - (2.
map): (a) がOkの場合にmapでfrom_serdeの結果をunwrap:=Ok<JsValue>またはErr<serde_json::error::Error>です - (3.
map_err): (a) または (b) の何れかがErr<serde_json::error::Error>の場合はmap_errでErr<JsValue>に変換されます
こうすると run の内部で Err<serde_json::error::Error> が発生しても Uncaught (in promise) missing filed `name` at line 1 column 104 のような console.error が吐かれるだけで、 run が使用不能には至らなくなります。
この他にも unwrap() により panic が発生する可能性がある部分はありますが、 GitHub が 404 になったり JSON レスポンスを廃止しない限りは事実上死には至らないです。学習用途ではなく実用する場合はより厳密に async/JsFuture の絡む内部で panic が発生しないように気にする必要はあります。