以下の内容はhttps://tategakibunko.hatenablog.com/entry/2022/09/08/172058より取得しました。


作品の長さに関係なく、高速に作品が表示されるようになりました

非同期処理への対応

wasm、js間の非同期処理に対応したことで、組版の完了したページを(全ページの計算の完了を待たずに)表示できるようになりました。

これによって、長編の作品も0.1 ~ 0.2秒ぐらいで表示されるようになり、使用感が改善されました。

技術的な部分

実はjsと非同期にやり取りする部分のコードのサンプルは、wasm_bindgenのサンプルに入っています。

https://github.com/rustwasm/wasm-bindgen/tree/main/examples/request-animation-frame

肝要なところを抜き出すと以下のようになります。

pub fn run() {
  let f = Rc::new(RefCell::new(None));
  let g = f.clone();
  let mut i = 0;

  *g.borrow_mut() = Some(Closure::new(|| {
    if i >= 300 {
      let _ = f.take();
      return;
    }
    i += 1;
    request_animation_frame(f.borrow().as_ref().unwrap());
  }));
  request_animation_frame(g.borrow().as_ref().unwrap());
}

fgはともにクロージャーを保持する参照カウント付きのポインタなのですが、gは最初にクロージャーを走らせるためだけに使います。

grunの終了後にクロージャーの参照カウントを減らしますが、もう一方のポインタfクロージャーの中で再帰的に参照され続けるため、何もしないとこのクロージャーに対する参照カウントは永遠にゼロにならず、解放されなくなってしまいます。

なのでreqest_animation_frameの処理を抜けるタイミングで、中身をf.take()で取り出し、スコープを抜けたところで解放されるようにしているわけですね。

基本は理解できるのですが、nehanの場合、上のサンプルにおけるクロージャーの自由変数が、もうちょっと複雑なデータになっていまして、これだけだと動かない部分があり、ハマっていたのです…

しかしまあ、色々と頑張ったら、なんとか動くようになったので、無事に縦書き文庫のビューアーが(以前と同じく)非同期にページを表示できるようになりました。

ちなみに上のrequest_animation_frameはもちろんjsの関数ではなく、rust側のweb_sysパッケージが提供している関数でして、たぶんですがrust側のデータをjs側のデータにいちいち「お直し」する処理が含まれると思われるため、あんまりたくさん呼ぶのはよくなさそうです。

なので、縦書き文庫の場合は、数十ページぐらい組版し、まとめて送信することで、jsとrust間の通信回数を減らすようにしています。

導入の成果

非同期処理に切り替えた結果、全ページを組版するのにかかる時間は、一度にすべて組版してから送信する方式よりは(当たり前ですが)少しだけ遅くなりました。

しかし、せいぜい5% ~ 10%ぐらいの遅延なので、許容範囲です。

作品を開いてから「しばらくお待ち下さい」の表示がなくなり、一瞬で作品が表示されるので、読者の離脱率も大きく改善されるものと思われます。




以上の内容はhttps://tategakibunko.hatenablog.com/entry/2022/09/08/172058より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14