1. ã¯ããã«
ããã«ã¡ã¯ãATOMäºæ¥é¨ããã³ãã¨ã³ãããã¯ãªã¼ãå
¼ãã¶ã¤ãã¼ã®æ²³åã§ãã
ä»åã¯ããã³ãã¨ã³ãã®éããå¦çãWeb WorkerãWebAssemblyãç¨ãã¦ã©ã®ããã«æ¹åã§ããããæ¤è¨¼ãããã®å¹æã測å®ãã¾ããã
ãã©ã¦ã¶ã¯åºæ¬çã«ã·ã³ã°ã«ã¹ã¬ããã¢ãã«ã§åä½ãã¾ããã¬ã³ããªã³ã°ãJavaScriptã®å®è¡ãCSSã®è§£éãªã©ãã¼ã¸ã表示ããããã«å¿
è¦ãªå¦çã1ã¤ã®ã¡ã¤ã³ã¹ã¬ããã§è¡ããã¾ãã
JavaScriptã§éããå¦çãè¡ãã¨ãä»ã®å¦çãå¾
ãããUXãèããæªåãã¾ãã
ä»åã¯JavaScriptã§éãå¦çãããå¿
è¦ãããç¶æ³ãä»®å®ãããããæ¹åããææ³ãå®è£
ãã¦å¦çæéãè¨æ¸¬ãã¾ããã
Web Worker
ã¹ã¯ãªããã®å¦çãã¡ã¤ã³ã¹ã¬ããã¨ã¯å¥ã®ã¹ã¬ããã«ç§»ããããã¯ã°ã©ã¦ã³ãã§ã®å®è¡ãå¯è½ã«ããä»çµã¿ã
ããã«ãããéããå¦çãã¡ã¤ã³ã¹ã¬ããå¤ã§å¦çãããã¨ãå¯è½ã¨ãªãã¾ãã
ãã ããã¡ã¤ã³ã¹ã¬ããã¨ã¡ã¢ãªç©ºéãå
±æã§ããªãããããã¼ã¿ã®ããåãã«ãªã¼ãã¼ããããä¼´ãã¾ãã
WebAssembly
ãã©ã¦ã¶ã§CãC++ãRustãªã©ã®ä½ã¬ãã«è¨èªããã³ã³ãã¤ã«ããããã¤ããªã³ã¼ããå®è¡ããæè¡ã
ããã«ãããé«éãªè¨ç®å¦çãå¯è½ã¨ãªãããã©ã¼ãã³ã¹ãåä¸ãããããã®è¨èªã®ã¨ã³ã·ã¹ãã ãå©ç¨å¯è½ã
ãã ããJavaScriptã¨ã®ããåãã«ãªã¼ãã¼ããããä¼´ãã¾ãã
ã¾ããDOMæä½ãHTTPãªã¯ã¨ã¹ãã¯JavaScriptãä»ãã¦è¡ãå¿
è¦ããããªã©å¶ç´ãããã¾ãã
2. æ¹åã¨è¨æ¸¬
ããã§ã¯ãå®éã«ããã©ã¼ãã³ã¹æ¹åã試ãã¦ããã¾ãããã æ¹åãããã·ããªãªã¯æ¬¡ã®ã¨ããã§ãã
- APIãµã¼ãã¼ãã3ä¸ä»¶ã®ã¬ã³ã¼ããåå¾ï¼ãã¼ã¿ãµã¤ãºã¯45MBç¨åº¦ï¼
- åå¾ããå ¨ã¬ã³ã¼ãã«å¯¾ãã¦å¤æå¦çãè¡ãï¼å ¨ä½ã§3ç§ç¨åº¦ãããï¼
ï¼éãå¦çã®è¯ãä¾ãæãã¤ãã¾ããã§ããï¼ã
ã¾ãã3ä¸ä»¶ãä¸åº¦ã«ãã§ããããåå²ãã¦ãã§ããããæ¹åæ¹æ³ããå¤æå¦çèªä½ã®ãã¸ãã¯æ¹åã¯ä»åã®æ¤è¨¼ã§ã¯è¡ããªãåæã¨ãã¾ãã
ä¸è¨ã·ããªãªã«å¯¾ãã¦5ã¤ã®ãµã³ãã«ãå®è£
ãã¾ããã
æ¬¡ç« ä»¥éã®åå¥ã®ãµã³ãã«èª¬æã§ã¯å®è£
ã¯ä¸é¨ã®ã¿ãæ示ã詳細ãªèª¬æã¯å²æãã¾ãã次ã®ãªãã¸ããªã«ãã¹ã¦ã®ã³ã¼ããããã¦ãã¾ãã
è¨æ¸¬ã®è©³ç´°ã¯æ¬¡ã®ã¨ããã
- MacBook Pro(M2)ã§è¨æ¸¬
- ãã¼ã«ã«ã§ãµã¼ããåãããåPCã«ã¦Chromeã§è¨æ¸¬
- ããã³ãã»ãµã¼ãã¨ãã®Next.jsã§ä½æ
- WebAssemblyã¯Rustã§ä½æ
- è¨æ¸¬æ¹æ³
- ã¦ã¼ã¶æä½ããå¤æå¦çãå®äºããã¾ã§ã«ããã£ãæéãè¨æ¸¬ï¼ã¬ã³ããªã³ã°ã¯å«ã¾ãªãï¼
- console.timeã§è¨æ¸¬ã3åã®å¹³åå¤ãçµæã¨ããã
- å¾åãã¿ãããã ãã®ãããè¨æ¸¬
2.1. ã¡ã¤ã³ã¹ã¬ããã§å¦çãã
ã¾ãã¯åºæ¬ã±ã¼ã¹ã¨ãã¦ã¡ã¤ã³ã¹ã¬ããã§ä½ãèããã«å¦çãããµã³ãã«ã§ãã
const data = await fetchJson("/api/examples"); // APIãµã¼ããããã§ãã const parsed = convertExampleList(data.list); // å¤æå¦çï¼3ä¸ã¬ã³ã¼ãã§ç´3sãããï¼
3554 ms
å®è¡ä¸ã®ç»é¢ãè¦ãã¨ããã¼ã«(ç½ä¸¸)ã®ã¢ãã¡ã¼ã·ã§ã³ãåæ¢ãã¦ããæéã確èªã§ãã¾ãããããå¤æå¦çãè¡ã£ã¦ããæéã§ãã ãã®æéã¯ã¦ã¼ã¶æä½ãå¾ ããããããç»é¢ãåºã¾ã£ã¦ããããã«æãã¾ãã
å¤æå¦çä¸ã®ãããã¡ã¤ã«çµæã§ããã¡ã¤ã³ã¹ã¬ãããJavascriptã®å¦çãã»ã¼å°æãã¦ãããã¨ããããã¾ãã
CSSã¢ãã¡ã¼ã·ã§ã³ã¯ããã©ã¦ã¶ã®æé©åã«ãã£ã¦ã¡ã¤ã³ã¹ã¬ããï¼CPUï¼ã§ã¯ãªãGPUã§å¦çããããã¨ãããã¾ãã GPUã§å¦çãããã¨ãã¢ãã¡ã¼ã·ã§ã³ãã¹ã ã¼ãºã«åä½ããã¡ã¤ã³ã¹ã¬ããã®è² è·ã軽æ¸ããã¾ãã ã¢ãã¡ã¼ã·ã§ã³ã«éãããGPUãæ´»ç¨ãããã¨ã¯ããã©ã¼ãã³ã¹æ¹åã«é常ã«å¹æçã§ãã ã¢ãã¡ã¼ã·ã§ã³ãGPUã§å¦çããããã©ããã¯ãå¤æ´ãããCSSããããã£ã«ãã£ã¦ç°ãªãã¾ãã 代表çãªããããã£ã¨ãã¦ã¯`transform`ã`opacity`ãããããããã¯ãªããã¼ããªãã¤ã³ããå¼ãèµ·ãããªããããé常ã¯GPUã§å¦çããã¾ãã
ä»åã®ãµã³ãã«ã§ã¯ããã¼ã«ã®é¨åã¯`top`ããããã£ãå¤æ´ãã¦ãã¾ãã`top`ã®å¤æ´ã¯ãªããã¼ãå¼ãèµ·ãããã¡ã¤ã³ã¹ã¬ããï¼CPUï¼ã§å¦çããã¾ãã ããã`transform: translateY`ãªã©ã§è¡¨ç¾ããã¨ãGPUã§å¦çãããå¯è½æ§ãé«ããªãã¾ãã ä»åã¯ãã¡ã¤ã³ã¹ã¬ããã®å°æç¶æ ãè¦è¦çã«ç¢ºèªã§ãããããããã¦`top`ãå¤åããã¦ãã¾ãã
â»ãªãããã©ã¦ã¶ã®è¨å®çç°å¢ã«ãã£ã¦ã¯GPUã使ãããªãå ´åãããã¾ãã
2.2. å¤æå¦çãWeb Workerã§å¦çãã
次ã¯æéã®ãããå¤æãWeb Workerã§å¦çãããµã³ãã«ã§ãã
// Main workerRef.current = new Worker(new URL("./worker.ts", import.meta.url)); workerRef.current.onmessage = (e: MessageEvent<ExampleItem[]>) => { setItems(e.data); }; ... const data = await fetchJson("/api/examples"); workerRef.current?.postMessage({ items: data.list }); // Worker const parsed = convertExampleList(items); postMessage(parsed);
3608 ms
ã2.1. ã¡ã¤ã³ã¹ã¬ããã§å¦çãããã¨æ¯è¼ããã¨55ms é ããªãã¾ããããç»é¢ã®åºã¾ãã¯è§£æ¶ãã¾ããã
é ããªã£ãè¦å ã¯ã¡ã¤ã³ã¹ã¬ããã¨Workerã¨ã®ããåãã«æéãããã£ã¦ããããã§ãã 3ä¸ä»¶ã®ãã¼ã¿ãããåããããããã¡ãã»ã¼ã¸ã®ã·ãªã¢ã©ã¤ã»ãã·ãªã¢ã©ã¤ãºçã«æéãããã£ã¦ããã¨èãããã¾ãã å®éã«ãã¡ã¤ã³ã¹ã¬ããã¨Workeréã®ãã¼ã¿ã®ããåãã ãã«ãããæéãè¨æ¸¬ããã¨ããã69ms ããã£ã¦ãã¾ããã
2.3. ãã¼ã¿ã®ãã§ãããWeb Workerã§å¦çãã
次ã¯ãã§ãããWorkerã§å¦çãããµã³ãã«ã§ãã ããã«ãããã¡ã¤ã³ã¹ã¬ããã¨Workeréã§ããã¨ãããé »åº¦ã¨ãã¼ã¿éãåæ¸ãããã¨ãã§ãã¾ãã
// Main workerRef.current = new Worker(new URL("./worker.ts", import.meta.url)); workerRef.current.onmessage = (e: MessageEvent<ExampleItem[]>) => { setItems(e.data); }; ... workerRef.current?.postMessage({}); // Worker const data = await fetchJson("/api/examples"); const parsed = convertExampleList(data.list as ExampleItem[]); postMessage(parsed);
3556 ms
ã2.1. ã¡ã¤ã³ã¹ã¬ããã§å¦çãããã¨æ¯è¼ãã¦å¦çæéã«ã»ã¨ãã©å·®ããªããç»é¢ã®åºã¾ãã解æ¶ãã¾ããã
2.4. WebAssemblyãå©ç¨ããï¼ã¡ã¤ã³ã¹ã¬ããï¼
次㯠WebAssemblyãå©ç¨ãããµã³ãã«ã§ããã¡ã¤ã³ã¹ã¬ããã§å®è¡ãã¾ãã
const wasm = await import("~/../wasm/pkg"); const res = await wasm.fetch_examples();
#[wasm_bindgen] pub async fn fetch_examples() -> Result<JsValue, JsValue> { let opts = RequestInit::new(); opts.set_method("GET"); opts.set_mode(RequestMode::Cors); let request = Request::new_with_str_and_init("/api/examples", &opts)?; let window = web_sys::window().unwrap(); JsFuture::from(window.fetch_with_request(&request)).await? let resp: Response = resp_value.dyn_into().unwrap(); let json: JsValue = JsFuture::from(resp.json()?).await?; let mut res: ExampleResponse = from_value(json).unwrap(); for item in &mut res.list { convert_example_item(item); } Ok(to_value(&res).unwrap()) }
2614 ms
ã2.1. ã¡ã¤ã³ã¹ã¬ããã§å¦çãããã¨æ¯è¼ã㦠940ms æ©ããªãã¾ããã ããããã¡ã¤ã³ã¹ã¬ããã§åä½ãããããçããªã£ãã¨ã¯ããç»é¢ã¯åºã¾ã£ãã¾ã¾ã§ãã
2.5. WebAssemblyã¨Web Workerãå©ç¨ãã
æå¾ã«WebAssemblyãWeb Workerã§å®è¡ãããµã³ãã«ã§ãã
// Worker const wasm = await import("~/../wasm/pkg"); const res = await wasm.fetch_examples(); postMessage(res.list);
#[wasm_bindgen] pub async fn fetch_examples() -> Result<JsValue, JsValue> { ... // ãã§ããé¨åãã¯ã¼ã«ã¼ã¹ã¬ãããèæ ®ããå®è£ ã¨ãªãããã以å¤ã¯2.4ã¨åãã let global = js_sys::global().unchecked_into::<web_sys::WorkerGlobalScope>(); JsFuture::from(global.fetch_with_request(&request)).await? ... }
2679 ms
ã2.1. ã¡ã¤ã³ã¹ã¬ããã§å¦çãããã¨æ¯è¼ã㦠875ms æ©ããªãã¾ããã ã¾ããç»é¢ã®åºã¾ãã解æ¶ãã¾ããã
ä»å試ããä¸ã§ã¯ãä¸çªè¯ãçµæã¨ãªãã¾ããã
3. ã¾ã¨ã
è¨æ¸¬çµæã®ã¾ã¨ãã§ãã
æ¹åæ¡ | å¦çæé | åè |
---|---|---|
2.1. ã¡ã¤ã³ã¹ã¬ããã§å¦çãã | 3554ms | ç»é¢ãåºã¾ã(NG) |
2.2. å¤æå¦çãWeb Workerã§å¦çãã | 3608ms | |
2.3. ãã¼ã¿ã®ãã§ãããWeb Workerã§å¦çãã | 3556ms | |
2.4. WebAssemblyãå©ç¨ããï¼ã¡ã¤ã³ã¹ã¬ããï¼ | 2614ms | ç»é¢ãåºã¾ã(NG) |
2.5. WebAssemblyã¨Web Workerãå©ç¨ãã | 2679ms |
ä»åã®ãµã³ãã«ã§ã¯ãWebAssemblyã¯å¦çæéãã®ãã®ãæ©ãããWeb Workerã¯ç»é¢ãåºã¾ããã¨ã解æ¶ãã¾ããã
ã©ã¡ããããã©ã¼ãã³ã¹æ¹åã«å¹æçã§ãããã¨ã確èªã§ãã¾ããã
ãã ããã©ã¡ããä¸è½ãªè§£æ±ºçã§ã¯ãªããç¶æ³ã«ããã¦ã¯æå¾
ã»ã©ã®æ§è½åä¸ãè¦ãããªãå ´åãããã¾ãã
ã¾ããç¹ã«WebAssemblyã«è¨ãã¾ãããå¦ç¿ã³ã¹ããé«ããããéçº/ä¿å®ã«ãããè²»ç¨ãå¢å ãããã¡ãªãããããã¾ãã
ãããã®æè¡ã¯ã¾ã çºå±ã®éä¸ã«ãããå°æ¥ã®ã¢ãããã¼ãã§ãããã«å¼·åãã¤ä½¿ãããããã¼ã«ã«ãªããã¨ãæå¾
ã§ãã¾ãã
ä¾ãã°ãWeb Workerã§ã¯ã¹ã¬ããéã§ã¡ã¢ãªãå
±æã§ãããSharedArrayBufferããç¾ç¶ã§ã¯ã»ãã¥ãªãã£ãªã¹ã¯ããã®å¶ç´ããã£ãããæååã®ããåãã®æéãããã£ããã¨ä½¿ãã¥ããç¹ãããã¾ãã
ãã®ç¹ã解æ¶ãããã¨ã¹ã¬ããéã®ããåãã®ãªã¼ãã¼ããããåæ¸ãããããã«ä½¿ãããããªãã¾ãã
ã¾ããWebAssemblyã§ã¯ãWeb Workerã«ä¾åããããä½ã¬ãã«ã§å¹ççãªä¸¦åå¦çãå¯è½ã«ãããCore Wasm Threadãã«æå¾
ãã¦ã¾ãï¼ãã§ã«ä¸é¨ä½¿ããã®ããªï¼ï¼ã
é²åã®ã¹ãã¼ããéããã£ããã¢ããã追ãã¤ãã¦ãã¾ããããä»å¾ãç¶ç¶çã«ãã£ããã¢ããããæ¤è¨¼ãé²ãã¦ããããã¨æãã¾ãã