การตรวจหาฟีเจอร์ WebAssembly

ดูวิธีใช้ฟีเจอร์ WebAssembly ใหม่ล่าสุดไปพร้อมกับสนับสนุนผู้ใช้ในทุกเบราว์เซอร์

WebAssembly 1.0 เปิดตัวเมื่อ 4 ปีก่อน แต่การพัฒนาไม่ได้หยุดอยู่แค่นั้น เราเพิ่มฟีเจอร์ใหม่ๆ เข้ามาผ่านทางกระบวนการกำหนดมาตรฐานข้อเสนอ เช่นเดียวกับในกรณีของฟีเจอร์ใหม่บนเว็บ ลำดับการใช้งานและลำดับเวลาของเครื่องมือทั้งสองอาจแตกต่างกันอย่างมาก หากต้องการใช้ฟีเจอร์ใหม่เหล่านั้น คุณต้องตรวจสอบว่าไม่มีผู้ใช้รายใดถูกทิ้ง ในบทความนี้ คุณจะได้ทราบแนวทางในการบรรลุเป้าหมายนี้

ฟีเจอร์ใหม่ๆ บางอย่างช่วยปรับปรุงขนาดของโค้ดได้ด้วยการเพิ่มคำสั่งใหม่สำหรับการดำเนินการทั่วไป บางฟีเจอร์เพิ่มข้อมูลพื้นฐานด้านประสิทธิภาพที่ทรงประสิทธิภาพ และอื่นๆ เพื่อปรับปรุงประสบการณ์ของนักพัฒนาซอฟต์แวร์และการผสานรวมกับเวอร์ชันอื่นๆ บนเว็บ

ดูรายการข้อเสนอทั้งหมดและขั้นตอนที่เกี่ยวข้องได้ในที่เก็บอย่างเป็นทางการ หรือติดตามสถานะการติดตั้งใช้งานในเครื่องมือได้ในหน้าแผนกลยุทธ์ของฟีเจอร์อย่างเป็นทางการ

คุณต้องพิจารณาก่อนว่าคุณต้องการใช้ฟีเจอร์ใด เพื่อให้แน่ใจว่าผู้ใช้ทุกเบราว์เซอร์จะสามารถใช้แอปพลิเคชันของคุณได้ จากนั้นจึงแยกผลิตภัณฑ์ออกเป็นกลุ่มตามการรองรับของเบราว์เซอร์ จากนั้นคอมไพล์ฐานของโค้ดสำหรับแต่ละกลุ่มแยกกัน สุดท้าย คุณต้องตรวจหาฟีเจอร์ที่รองรับและโหลดแพ็กเกจ JavaScript และ Wasm ที่เกี่ยวข้องทางเบราว์เซอร์

การเลือกและจัดกลุ่มฟีเจอร์

ลองมาดูขั้นตอนเหล่านี้โดยเลือกชุดฟีเจอร์ที่กำหนดเองเป็นตัวอย่าง สมมติว่าฉันต้องการใช้การจัดการ SIMD, ชุดข้อความ และข้อยกเว้นในคลังเพื่อเหตุผลด้านขนาดและประสิทธิภาพ โดยมีการรองรับเบราว์เซอร์ดังต่อไปนี้

วันที่ ตารางแสดงการรองรับเบราว์เซอร์ของฟีเจอร์ที่เลือก
ดูตารางฟีเจอร์นี้ได้ที่ webassembly.org/roadmap

คุณสามารถแบ่งเบราว์เซอร์ออกเป็นกลุ่มประชากรตามรุ่นต่อไปนี้เพื่อให้ผู้ใช้แต่ละรายได้รับประสบการณ์การเพิ่มประสิทธิภาพสูงสุด

  • เบราว์เซอร์แบบ 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++ ได้โดยไม่คำนึงถึงการติดตั้งใช้งานเบื้องหลังที่เลือกผ่านแฟล็กการคอมไพล์

กำลังโหลดชุดข้อมูลที่ถูกต้อง

เมื่อสร้าง 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 ในเบราว์เซอร์ทั้งหมด