การตรวจหาฟีเจอร์ 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++ ได้ ไม่ว่าจะเลือกการใช้งานที่จำเป็นผ่านแฟล็กการคอมไพล์หรือไม่ก็ตาม

กำลังโหลดแพ็กเกจที่ถูกต้อง

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

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 ในทุกเบราว์เซอร์