تشخیص ویژگی WebAssembly

با نحوه استفاده از جدیدترین ویژگی های WebAssembly در حین پشتیبانی از کاربران در همه مرورگرها آشنا شوید.

WebAssembly 1.0 چهار سال پیش منتشر شد، اما توسعه در اینجا متوقف نشد. ویژگی های جدید از طریق فرآیند استانداردسازی پیشنهاد اضافه می شود. همانطور که به طور کلی در مورد ویژگی های جدید در وب صادق است، ترتیب اجرای آنها و جدول زمانی آنها می تواند به طور قابل توجهی بین موتورهای مختلف متفاوت باشد. اگر می‌خواهید از این ویژگی‌های جدید استفاده کنید، باید اطمینان حاصل کنید که هیچ یک از کاربران شما کنار گذاشته نمی‌شوند. در این مقاله با روشی برای دستیابی به این هدف آشنا خواهید شد.

برخی ویژگی‌های جدید با افزودن دستورالعمل‌های جدید برای عملیات رایج، اندازه کد را بهبود می‌بخشند، برخی عملکردهای اولیه قدرتمند را اضافه می‌کنند، و برخی دیگر تجربه توسعه‌دهنده و ادغام با بقیه وب را بهبود می‌بخشند.

شما می توانید لیست کامل پیشنهادات و مراحل مربوطه آنها را در مخزن رسمی بیابید یا وضعیت اجرای آنها را در موتورها در صفحه نقشه راه رسمی ویژگی پیگیری کنید.

برای اطمینان از اینکه کاربران همه مرورگرها می توانند از برنامه شما استفاده کنند، باید مشخص کنید که می خواهید از کدام ویژگی استفاده کنید. سپس، آنها را بر اساس پشتیبانی مرورگر به گروه‌هایی تقسیم کنید. سپس، پایگاه کد خود را به طور جداگانه برای هر یک از آن گروه ها کامپایل کنید. در نهایت، در سمت مرورگر باید ویژگی‌های پشتیبانی شده را شناسایی کرده و جاوا اسکریپت و بسته Wasm مربوطه را بارگیری کنید.

انتخاب و گروه بندی ویژگی ها

بیایید با انتخاب برخی از ویژگی‌های دلخواه به عنوان نمونه، آن مراحل را طی کنیم. فرض کنید من تشخیص داده‌ام که به دلایل اندازه و عملکرد می‌خواهم از SIMD، رشته‌ها و مدیریت استثنا در کتابخانه‌ام استفاده کنم. پشتیبانی مرورگر آنها به شرح زیر است:

جدولی که پشتیبانی مرورگر از ویژگی های انتخاب شده را نشان می دهد.
این جدول ویژگی را در webassembly.org/roadmap مشاهده کنید.

می‌توانید مرورگرها را به گروه‌های زیر تقسیم کنید تا مطمئن شوید که هر کاربر بیشترین تجربه را دارد:

  • مرورگرهای مبتنی بر کروم: موضوعات، SIMD و مدیریت استثنا همگی پشتیبانی می‌شوند.
  • فایرفاکس: Thread و SIMD پشتیبانی می شوند، مدیریت استثناها پشتیبانی نمی شود.
  • Safari: Thread ها پشتیبانی می شوند، SIMD و مدیریت استثناها پشتیبانی نمی شوند.
  • سایر مرورگرها: فرض کنید که فقط از WebAssembly پشتیبانی می کند.

این تفکیک بر اساس پشتیبانی از ویژگی ها در آخرین نسخه هر مرورگر تقسیم می شود. مرورگرهای مدرن همیشه سبز هستند و به‌روزرسانی خودکار هستند، بنابراین در اکثر موارد فقط باید نگران آخرین نسخه باشید. با این حال، تا زمانی که WebAssembly پایه را به‌عنوان یک گروه بازگشتی در نظر بگیرید، همچنان می‌توانید یک برنامه کاربردی حتی برای کاربرانی با مرورگرهای قدیمی ارائه دهید.

کامپایل برای مجموعه ویژگی های مختلف

WebAssembly یک روش داخلی برای شناسایی ویژگی های پشتیبانی شده در زمان اجرا ندارد، بنابراین تمام دستورالعمل های ماژول باید روی هدف پشتیبانی شوند. به همین دلیل، شما باید کد منبع را به طور جداگانه برای هر یک از مجموعه ویژگی های مختلف در Wasm کامپایل کنید.

هر زنجیره ابزار و سیستم ساخت متفاوت است، و برای اینکه چگونه آن ویژگی ها را بهینه کنید باید با مستندات کامپایلر خود مشورت کنید. برای سادگی، در مثال زیر از کتابخانه C++ تک فایلی استفاده می کنم و نحوه کامپایل آن را با Emscripten نشان می دهم.

من از SIMD از طریق شبیه‌سازی SSE2 ، رشته‌ها از طریق پشتیبانی از کتابخانه Pthreads استفاده می‌کنم و بین مدیریت استثنا Wasm و پیاده‌سازی جاوا اسکریپت بازگشتی را انتخاب می‌کنم:

# 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++ بدون توجه به پیاده‌سازی اساسی انتخاب شده از طریق پرچم‌های کامپایل استفاده کرد.

در حال بارگیری بسته صحیح

هنگامی که بسته‌هایی را برای همه گروه‌های ویژگی ایجاد کردید، باید مورد صحیح را از برنامه اصلی جاوا اسکریپت بارگیری کنید. برای انجام این کار، ابتدا شناسایی کنید که کدام ویژگی ها در مرورگر فعلی پشتیبانی می شوند. می توانید این کار را با کتابخانه 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 در همه مرورگرها باقی می‌ماند.