ดูวิธีใช้ฟีเจอร์ WebAssembly ใหม่ล่าสุดขณะที่รองรับผู้ใช้ในทุกเบราว์เซอร์
WebAssembly 1.0 เปิดตัวเมื่อ 4 ปีก่อน แต่การพัฒนาไม่ได้หยุดอยู่แค่นั้น ฟีเจอร์ใหม่จะเพิ่มผ่านกระบวนการกำหนดมาตรฐานข้อเสนอ โดยทั่วไปแล้ว ลำดับเวลาและลำดับการนำฟีเจอร์ใหม่มาใช้ในเครื่องมือต่างๆ นั้นอาจแตกต่างกันอย่างมาก หากต้องการใช้ฟีเจอร์ใหม่เหล่านั้น คุณต้องตรวจสอบว่าผู้ใช้ทุกคนได้รับฟีเจอร์ดังกล่าว ในบทความนี้ คุณจะได้ทราบแนวทางในการบรรลุเป้าหมายนี้
ฟีเจอร์ใหม่บางรายการจะปรับปรุงขนาดโค้ดด้วยการเพิ่มคำสั่งใหม่สำหรับการดำเนินการทั่วไป บางรายการจะเพิ่มองค์ประกอบพื้นฐานที่มีประสิทธิภาพสูง และบางรายการจะปรับปรุงประสบการณ์การใช้งานของนักพัฒนาซอฟต์แวร์และการผสานรวมกับส่วนอื่นๆ ของเว็บ
คุณดูรายการข้อเสนอทั้งหมดและระยะต่างๆ ที่เกี่ยวข้องได้ใน repo อย่างเป็นทางการ หรือติดตามสถานะการใช้งานในเครื่องมือต่างๆ ได้ในหน้าแผนกลยุทธ์ฟีเจอร์อย่างเป็นทางการ
คุณต้องพิจารณาว่าต้องการใช้ฟีเจอร์ใดเพื่อให้ผู้ใช้เบราว์เซอร์ทุกประเภทสามารถใช้แอปพลิเคชันของคุณได้ จากนั้นแบ่งออกเป็นกลุ่มตามการรองรับเบราว์เซอร์ จากนั้นคอมไพล์โค้ดเบสแยกกันสำหรับแต่ละกลุ่ม สุดท้าย คุณต้องตรวจหาฟีเจอร์ที่รองรับและโหลด JavaScript และ Wasm Bundle ที่เกี่ยวข้องในฝั่งเบราว์เซอร์
การเลือกและจัดกลุ่มฟีเจอร์
มาดูขั้นตอนต่างๆ กันโดยเลือกชุดฟีเจอร์แบบสุ่มเป็นตัวอย่าง สมมติว่าฉันต้องการใช้การจัดการ SIMD, ชุดข้อความ และข้อยกเว้นในคลังเพื่อเหตุผลด้านขนาดและประสิทธิภาพ โดยมีการรองรับเบราว์เซอร์ดังต่อไปนี้
คุณสามารถแบ่งเบราว์เซอร์ออกเป็นกลุ่มประชากรตามรุ่นต่อไปนี้เพื่อให้ผู้ใช้แต่ละคนได้รับประสบการณ์การใช้งานที่ดีที่สุด
- เบราว์เซอร์แบบ Chrome: ระบบรองรับการจัดการชุดข้อความ, SIMD และข้อยกเว้นทั้งหมด
- Firefox: ระบบรองรับเทรดและ SIMD แต่ไม่สามารถจัดการข้อยกเว้น
- Safari: รองรับเธรด แต่ไม่รองรับ SIMD และการจัดการข้อยกเว้น
- เบราว์เซอร์อื่น: จะถือว่ามีเพียงการรองรับ WebAssembly พื้นฐานเท่านั้น
รายละเอียดนี้แบ่งตามการรองรับฟีเจอร์ในเบราว์เซอร์แต่ละเวอร์ชันล่าสุด เบราว์เซอร์สมัยใหม่เป็นเบราว์เซอร์ที่ใช้งานได้ตลอดและอัปเดตอัตโนมัติ คุณจึงไม่ต้องกังวลเกี่ยวกับรุ่นล่าสุดในเกือบทุกกรณี อย่างไรก็ตาม ตราบใดที่คุณรวม WebAssembly พื้นฐานไว้เป็นกลุ่มประชากรตามรุ่นสำรอง คุณก็จะยังคงให้บริการแอปพลิเคชันที่ใช้งานได้แม้กับผู้ใช้ที่มีเบราว์เซอร์ล้าสมัย
การคอมไพล์สําหรับชุดฟีเจอร์ต่างๆ
WebAssembly ไม่มีวิธีในตัวสำหรับตรวจหาฟีเจอร์ที่รองรับในรันไทม์ จึงต้องรองรับวิธีการทั้งหมดในโมดูลนี้ในเป้าหมาย คุณจึงต้องคอมไพล์ซอร์สโค้ดเป็น Wasm แยกกันสำหรับชุดฟีเจอร์แต่ละชุด
เครื่องมือและระบบบิลด์แต่ละชุดจะแตกต่างกันไป คุณจึงต้องดูเอกสารประกอบของคอมไพเลอร์ของคุณเองเพื่อดูวิธีปรับแต่งฟีเจอร์เหล่านั้น เราจะใช้ไลบรารี C++ แบบไฟล์เดียวในตัวอย่างต่อไปนี้เพื่อลดความซับซ้อน และแสดงวิธีคอมไพล์ด้วย Emscripten
ฉันจะใช้ SIMD ผ่านการจําลอง SSE2, เทรดผ่านการสนับสนุนไลบรารี Pthreads และเลือกระหว่างการจัดการข้อยกเว้น Wasm กับการใช้งาน JavaScript สำรอง ดังนี้
# First bundle: threads + SIMD + Wasm exceptions
$ emcc main.cpp -o main.threads-simd-exceptions.mjs -pthread -msimd128 -msse2 -fwasm-exceptions
# Second bundle: threads + SIMD + JS exceptions fallback
$ emcc main.cpp -o main.threads-simd.mjs -pthread -msimd128 -msse2 -fexceptions
# Third bundle: threads + JS exception fallback
$ emcc main.cpp -o main.threads.mjs -pthread -fexceptions
# Fourth bundle: basic Wasm with JS exceptions fallback
$ emcc main.cpp -o main.basic.mjs -fexceptions
โค้ด C++ เองสามารถใช้ #ifdef __EMSCRIPTEN_PTHREADS__
และ #ifdef __SSE2__
เพื่อเลือกแบบมีเงื่อนไขระหว่างการใช้งานแบบขนาน (เธรดและ SIMD) ของฟังก์ชันเดียวกันกับการใช้งานแบบอนุกรม ณ เวลาคอมไพล์ ซึ่งจะมีลักษณะดังนี้
void process_data(std::vector<int>& some_input) {
#ifdef __EMSCRIPTEN_PTHREADS__
#ifdef __SSE2__
// …implementation using threads and SIMD for max speed
#else
// …implementation using threads but not SIMD
#endif
#else
// …fallback implementation for browsers without those features
#endif
}
การจัดการข้อยกเว้นไม่จำเป็นต้องใช้คำสั่ง #ifdef
เนื่องจากสามารถใช้งานได้ในลักษณะเดียวกับจาก C++ ไม่ว่าจะใช้การใช้งานพื้นฐานที่เลือกผ่าน Flag การคอมไพล์หรือไม่ก็ตาม
กำลังโหลด Bundle ที่ถูกต้อง
เมื่อสร้างกลุ่มประชากรตามรุ่นของฟีเจอร์ทั้งหมดแล้ว คุณต้องโหลดกลุ่มประชากรตามรุ่นที่ถูกต้องจากแอปพลิเคชัน JavaScript หลัก โดยวิธีแรกคือตรวจหาฟีเจอร์ที่เบราว์เซอร์ปัจจุบันรองรับ ซึ่งทำได้โดยใช้ไลบรารี wasm-feature-detect เมื่อใช้ร่วมกับการนําเข้าแบบไดนามิก คุณจะโหลดแพ็กเกจที่เพิ่มประสิทธิภาพสูงสุดในเบราว์เซอร์ใดก็ได้ โดยทําดังนี้
import { simd, threads, exceptions } from 'https://unpkg.com/wasm-feature-detect?module';
let initModule;
if (await threads()) {
if (await simd()) {
if (await exceptions()) {
initModule = import('./main.threads-simd-exceptions.mjs');
} else {
initModule = import('./main.threads-simd.mjs');
}
} else {
initModule = import('./main.threads.mjs');
}
} else {
initModule = import('./main.basic.mjs');
}
const Module = await initModule();
// now you can use `Module` Emscripten object like you normally would
สรุป
ในโพสต์นี้ เราจะแสดงวิธีเลือก สร้าง และสลับระหว่างแพ็กเกจสำหรับชุดฟีเจอร์ต่างๆ
เมื่อจํานวนฟีเจอร์เพิ่มขึ้น จํานวนกลุ่มประชากรตามรุ่นของฟีเจอร์อาจไม่สามารถดูแลรักษาได้ หากต้องการบรรเทาปัญหานี้ คุณสามารถเลือกกลุ่มประชากรตามข้อมูลผู้ใช้ในชีวิตจริง ข้ามเบราว์เซอร์ที่ไม่ค่อยได้รับความนิยม และปล่อยให้กลุ่มประชากรเหล่านั้นกลับไปใช้กลุ่มประชากรที่มีประสิทธิภาพน้อยลงเล็กน้อย ตราบใดที่แอปพลิเคชันยังคงใช้งานได้สำหรับผู้ใช้ทุกคน แนวทางนี้จะช่วยให้คุณรักษาสมดุลที่เหมาะสมระหว่างการเพิ่มประสิทธิภาพแบบเป็นขั้นเป็นตอนกับประสิทธิภาพรันไทม์ได้
ในอนาคต WebAssembly อาจมีวิธีตรวจหาฟีเจอร์ที่รองรับและเปลี่ยนระหว่างการใช้งานฟังก์ชันเดียวกันในโมดูลต่างๆ ในตัว อย่างไรก็ตาม กลไกดังกล่าวจะเป็นฟีเจอร์หลัง MVP ที่คุณจะต้องตรวจหาและโหลดแบบมีเงื่อนไขโดยใช้แนวทางข้างต้น ในระหว่างนี้ แนวทางนี้จะยังคงเป็นวิธีเดียวในการสร้างและโหลดโค้ดโดยใช้ฟีเจอร์ WebAssembly ใหม่ในเบราว์เซอร์ทั้งหมด