Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Web workerを使ってUXを向上させようとした話
Search
kurisaki kazuma
September 26, 2023
1
300
Web workerを使ってUXを向上させようとした話
We Are JavaScripters! @42nd で発表した資料です。
WeJs
https://wajs.connpass.com/event/293440/
kurisaki kazuma
September 26, 2023
Tweet
Share
More Decks by kurisaki kazuma
See All by kurisaki kazuma
Next13 動的クエリ、 Server component で実装するか?Client component で実装するか?
kult0922
0
160
Featured
See All Featured
Web Components: a chance to create the future
zenorocha
306
41k
How to name files
jennybc
65
93k
Robots, Beer and Maslow
schacon
PRO
155
7.9k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
14
1.5k
Put a Button on it: Removing Barriers to Going Fast.
kastner
58
3.1k
A better future with KSS
kneath
231
16k
Automating Front-end Workflow
addyosmani
1357
200k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
126
32k
The Power of CSS Pseudo Elements
geoffreycrofte
62
5k
jQuery: Nuts, Bolts and Bling
dougneiner
59
7.2k
The Illustrated Children's Guide to Kubernetes
chrisshort
32
46k
How To Stay Up To Date on Web Technology
chriscoyier
782
250k
Transcript
Web worker を使って UX を向上させようとした話 1
自己紹介 栗崎一真 フロントエンドエンジニア 2021 卒 楽天グループ株式会社 AI SHIFT (サイバーエージェント) X:
@KK_sep_TT GitHub: @kult0922 趣味 個人開発 旅行 ポーカー 2
はじめに 写真からマインクラフトのドット絵に変換するサービスを開発しています https://www.minecraft-dot.pictures 3
UX 改善したいところ 変換中に画面が固まらないようにしたい JS で画像処理を行っているので画面をロックしてしまう 変換中はローディングのアニメーションを出したい あったら嬉しい機能 変換の進捗を表示したい 4
なぜ画面がロックされてしまうのか JS は画面の処理をメインスレッドで行う メインスレッドで重い処理を行うと処理中は画面処理にリソースを使えない 5
そこで Web worker を使う Web worker とは メインスレッドとは独立して JS をバックグラウンドで実行できる
Web API メインスレッドのパフォーマンスに影響を与えず、時間のかかる処理ができる。 メインスレッドとは別なので UI をロックしない 6
Worker の使い方 worker を呼び出す側 worker = new Worker("worker.js"); // worker
から結果を受け取る worker.onmessage = function (event) { console.log("Received: ", event.data); }; worker.postMessage(10); // worker に 10 を引数で渡して実行 worker.js self.addEventListener("message", (e) => { const result = e.data * e.data; postMessage(result); }); 7
どこを Worker に切り出すか 時間の掛かっている処理を worker 内で行う 設計図からドット画像を構築するろころで時間がかかっていた 8
作成した Worker const constructImageFromBlueprint = (blueprint: Array<Array<string>>) => { //
設計図からドット画像を構築する処理 ... return result; }; self.addEventListener("message", (e) => { const result = constructImageFromBlueprint(e.data.blueprint); self.postMessage(result); }); 9
カスタムフックで worker の状態を管理 export function useWorker() { const [loading, setLoading]
= useState(true); const run = ( ) => { setLoading(true); const worker = new Worker( new URL("./worker", import.meta.url) ); worker.onmessage = function (e) { // worker 処理完了 setLoading(false); ... }; worker.postMessage({ blueprint, blockImageDataDict }); }; return { loading, run }; } 10
ここまで 画面のロックを防ぎたい ローディングを表示したい 進捗を知りたい 11
worker 側から進捗を伝える worker とメインスレッドの共有方法は基本的には message だけ 進捗も結果と同様 message として送る type
プロパティで進捗地なのか結果なのかを判定 const constructImageFromBlueprint = (blueprint: Array<Array<string>>) => { for (let i = 0; i < rows; i++) { if (i % step === 0) { progress += stepNum; self.postMessage({ type: "loading", payload: progress, }); } ... } self.postMessage({ type: "complete", payload: result, }); }; 12
カスタムフックも進捗を受け取るように修正 export function useImageGeneratorWorker() { const [progress, setProgress] = useState(0);
// 進捗 const [loading, setLoading] = useState(true); const run = (blueprint: string[][]) => { setLoading(true); const worker = new Worker( new URL("../worker/imageGeneratorWorker", import.meta.url) ); worker.onmessage = function (e) { if (e.data.type == "loading") { setProgress(e.data.payload); // <- 進捗を受け取る return; } setLoading(false); }; worker.postMessage({ blueprint, blockImageDataDict }); }; return { progress, loading, run }; // <- 進捗も返す } 13
結果 https://www.minecraft-dot.pictures 14
requestAnimationFrame との比較 同じようなことは requestAnimationFrame をつかってもできる。 worker マルチスレッドなので環境によってはパフォーマンスがいい worker ファイルを作成して message
でメインスレッドとやり取り message のやり取りはコピーなので大きいデータのやり取りでパフォーマンスが落ちる 可能性がある reauestnimationFrame シングルスレッドですべての処理を行う 重い処理を関数に分割して再帰的に実行 15
まとめ Web worker を使用することでメインスレッドをロックせずに重い処理を実行 進捗も message で送ることでプログレスバーを実装 16
17