وب اسمبلی یک راه برای اجرای کد نوشته شده توسط زبان های مختلف (معمولا سیستمی) بر روی مرورگر، با سرعت نزدیک به سرعت اجرای آنها به صورت Native است. در حقیقت وب اسمبلی یک استاندارد برای تعریف فرمت کد باینری هست که در وب و مرورگر قابل اجرا است. در ادامه به وب اسمبلی چیست و ویژگی های آن می پردازیم.
دلیل ساخت وب اسمبلی چیست ؟
JS در سال 1995 ارائه شده و در زمان طراحی آن بر روی پرسرعت بودنش تمرکزی نشده، چرا که هدف از طراحی این زبان موضوع دیگه ای بوده، این زبان با هدف افزودن پویایی و کنترل بیشتر بر روی محتوا، ساختار و استایل صفحات وب (کاری که DOM انجام میده) طراحی شده بود. یکی از ویژگی های اصلی که کار با این زبان رو راحت می کرد، Dynamic بودن Type های این زبان بوده، به این معنی که یه متغیر در زمان اجرا میتونه در لحظات مختلف، نوع های مختلف داشته باشه. این موضوع شاید به ساده شدن کار با JS کمک کنه ولی یک Trade-off بزرگ بین کارایی (Performance) و سادگی کار با زبان بوجود آورده.
البته این Trade-off به طور کلی بین زبان های Static-Typed و Dynamic-Typed وجود داشته و داره، و یکی از دلایل برتری کارایی و سرعت زبان هایی مثل C,C++ و Rust در مقایسه با Python، JS هست. در عوض، سرعت نوشتن و توسعه برنامه هایی که با زبان های Dynamic نوشته میشن، چندین برابر دیگر زبان های Static هست و دلیل اصلی که Startup ها علاقه زیادی به ای زبان ها دارند هم همینه. البته این زبان های Dynamic در طی سال ها سعی کردند که با استفاده از روش های مختلف سرعتشون رو به سرعت Native زبان های Static نزدیک تر کنند و حتی در این بین نیز زبان هایی آمدند که از ویژگی های هر دو طرف بهره می برند. WebAssembly نقش یک پل رو بین JS و زبان هایی با کارایی بیشتر ایفا می کنه.
البته JS طی سال های متوالی سریع تر و سریع تر شده و اگه با کتابخانه asm.js آشنا باشید، می دونید که میشه باهاش اپلیکیشن های بزرگی مثل موتور های بازی رو اجرا کرد. ولی باز با این حال، مشکل فراتر از این حرف هاست و بهترین کارایی ممکن JS، باز برای کار های پیچیده، کم هست. این کار نیاز داره که از پایه طراحی ما کارایی گرا باشه. یعنی باید طراحی در سطح فرمت اجرایی کد باشه (همون Assembly) و وب اسمبلی هدف انجام چنین کاری رو داره.
از طرفه دیگه JS طوری طراحی شده که نوشتن و خواندن کدش راحت تر باشه ولی وب اسمبلی با هدف بیشینه کردن کارایی توسط کامپایلر طزاحی شده.
WebAssembly قراره چطور به ما کمک کنه؟
قبل از اینکه بریم سراغ چگونگی کارکرد وب اسمبلی، بریم سراغ اینکه اصلا این وب اسمبلی به چه دردی قراره بخوره؟
همونطور که در این ویدیو از Mozilla میتونید ببینید، وب اسمبلی در دو حوزه به توسعه دهنده گان میتونه کمک کنه :
- زمان بارگذاری اولیه (StartUp Time)
گذشته زمانی که از JS فقط برای Validate کردن فرم ها و یا ارسال درخواست به سمت سرور استفاده بشه، امروزه با JS در سمت کلاینت فریم ورک هایی رو داریم میبینیم که برای ساخت وب اپلیکیشن های مدرن، با ظاهری مناسب و سرعت بالا طراحی شدند، از جمله سه غول بزرگ وب یعنی React، Vue و Angular.
Angular به خودی خودش شامل پانصد هزار خط کد هست که به خوبی رشد و تکامل برنامه های نوشته شده با JS رو نشون می ده. این نکته رو هم در نظر بگیرید که کامپایلر زبان رو به رشد Rust یعنی rustc شامل هفتصد هزار خط کد هست. در نتیجه این پلتفرم ها و فریم ورک های بزرگ، نیاز به انتقال حجم بالایی از اطلاعات از سمت سرور به کلاینت خواهند داشت. کد تولید شده توسط WebAssembly یک bytecode هست و میتونه از کد JS حجم کمتری داشته باشه و راحت تر Compress شه.
- توان عملیاتی بیشتر (Throughput)
علاوه بر حجم بالای کد های نوشته شده بوسیله زبان JS، پیچیدگی و زمان مورد نیاز برای دریافت، تحلیل یا (Parse)، کامپایل و در نهایت اجرای کد JS بیشتر و بیشتر شده. و زبان JS (همونطور که اول گفتم) برای این کار های پیچیده طراحی نشده و طبیعی هست که این کار هارو با کارایی کمتری انجام بده.
WebAssembly این امکان رو به زبان JS میده تا کار های پیچیده تر رو با کارایی بین ۲۰ تا ۸۰۰ درصد بالاتر انجام بده. در حقیقت WebAssembly این کار رو با اجرای کد کامپایل شده زبان های سطح متوسطی مثل C، C++ و RUST انجام میده و از JS فقط برای صدا زدن این کد های کامپایل شده به شکل یک تابع، کمک می گیره.
وضعیت جاوا اسکریپت در وجود وب اسمبلی چیست ؟
شاید شنیده باشید که وب اسمبلی قراره JS رو جایگزین کنه ولی این حرف درست نیست. درسته که کار ها و محاسبات سنگین از دوش JS برداشته میشه ولی بالاخره باید از JS برای ارتباط با DOM و ساختاردهی، مدیریت محتوا صفحه و استایل دهی پویا به اون، استفاده کرد. در حقیقت، JS و وب اسمبلی قراره که در کنار هم و با هم ما رو به سمت یک انقلاب بزرگ در حوضه اپلیکیشن های وب ببرند. حالا شاید بپرسید چرا انقلابی ؟
WebAssembly انقلابی در حوزه وب
فرض کنید میحواید یه برنامه کاربردی (Application) جدید برای سیستم عاملتون نصب کنید و ازش استفاده کنید. چی کار میکنید؟ اول باید فایل نصبی رو گیر بیارید، دانلود کنید، نصب کنید و بعد میشه اجراش کرد. حالا دنیایی رو فرض کنید که داخلش، مرورگرتونو باز می کنید، یه ادرس داخلش وارد می کنید و بعد از باز شدن صفحه، می تونید با برنامتون کار کنید، به همین سادگی. توجه به چند تا نکته اینجا مهمه:
- به دانلود فایل نصب نیازی نیست.
- به نصب برنامه نیازی نیست.
- نرم افزار کاملا چند سکویی و Portable هست.
- نرم افزار کاملا امن هست و بدلیل سیاستهای امنیتی خود مرورگر ریسک امنیتی بحرانی وجود نداره.
کاربرد های وب اسمبلی چیست ؟
این لیست شامل لیست مرتب نشده از حوزه، برنامه و یا محاسباتی هست که وب اسمبلی میتونه به ما کمک کنه:
- نرم افزار های video editing و image editing
- بازی های رایانه ای تحت مرورگر
- اپلیکیشن های نظیر به نظیر (نرم افزار Editing و یا بازی های مشارکتی)
- اپلیکیشن های موسیقی (Streaming)
- VR و واقعیت افزوده
- شبیه سازی های علمی
- مفسر زبان و یا ماشین های مجازی
- ابزار های توسعه (کامپایلر، Editor)
- VPN
- رمزنگاری
- اپلیکیشن های سازمانی
- و …
کمی از تاریخچه وب اسمبلی
شروع کار بر روی وب اسمبلی از سال ۲۰۱۰ شروع شده. توسعه اولیه این تکنولوژی به عنوان سرگرمی توسط خالق اون یعنی Alon Zakai یاد میشه که بعد از مدتی به پروژه Emscripten تبدیل شده. در ابتدا این پروژه، کد C++ را به کد JS تبدیل می کرده و همونطور که انتظار هم میرفت، ۵ یا ۴ برابر کند تر از کد معادل C++ بوده. بعد از کمی بهینه تر کردن این کد، کتابخانه asm.js خلق میشه. در این مرحله حتی موتور های بازی هم میتونستن به JS تبدیل شن و در مرورگر اجرا شن. خالقین asm.js با کنجکاوی میرن سمت کمپانی های بازی سازی و پورت کردن بازی های اونا داخل وب رو به عنوان یه چالش قبول می کنن. پس از کمی تبلیغ و سرو صدا کردن این تکنولوژی و البته کمی مذاکره بین مرورگر ها، وب اسمبلی خلق میشه.
WebAssembly چطور کار می کنه؟
حالا بریم سراغ قسمت جالب قضیه، اینکه چطور WebAssembly کار می کنه؟ برای اینکه یه برنامه JS روی مرورگر اجرا شه، باید مراحل زیر صورت بگیره، این مراحل در برنامه های مختلف زمان های مختلی می گیرن ولی به طور میانگین نسبتی مثل شکل زیر دارن:
حالا بیاید یه نگاهی به نسخه WebAssembly این نمودار بندازیم:
متوجه میشیم که برخی از اجزا اصلا نیستند و برخی هم خیلی کوتاه تر شدند. حالا بریم ببینیم چطور این اتفاق در عمل افتاده. برای توضیح این موضوع یه سر به کامپایلر های JIT یا Just-in-time باید بندازیم. اگر میخواید به صورت کامل یاد بگیرید که جاوا اسکریپت چطوری کار میکنه می توید این مقاله رو بخونید: درک نحوه کارکرد کامپایلر جاوا اسکریپت
در سال های اول، JS به صورت زیر اجرا میشده:
یعنی اگر JIT نبود، اجرای کد خیلی بیشتر طور می کشید و الان کد های JS ما ۱۰ ها بار کند تر بودند. حالا این JIT چیکار می کنه که اجرای این کد، انقدر سریع میشه؟ دقت کنید که مرحله Compile و Optimize به نمودار JIT اضافه شده و این سربار استفاده از JIT هست.
حالا کامپایلر های JIT چیکار می کنن؟ در کل دو راه برای فهماندن منظورتون به کامپیوتر دارید، یکی اینکه کد رو برای ماشین تفسیر کنید و یا اینکه اون کد رو براش کامپایل کنید. مفسر خط به خط منبع کد رو می خونه و همون لحظه کد رو به کد ماشین تبدیل میکنه و بعد اونو اجرا میکنه. ولی یه کامپایلر کل منبع کد رو باید در اختیار داشته باشه که پیش از اجرای اون تمام کد رو تبدیل به کد ماشین کنه.
حالا مزایا و معایب هر کدوم از این روش ها چیه؟ در روش مفسر، کد به سرعت شروع به اجرا میکنه و نیازی به صبر کردن اضافی برای اجرای اون نیست . به راحتی میشه از کد نوشته شده بازخورد گرفت. این یکی از نیاز های اساسی زبان JS هست که به کاربر این اجازه رو میده که راحت تر و با سرعت بالاتری کد ها رو توسعه بده. ولی خوب، بدی این کار چیه؟ اگه قرار باشه این کد بار ها و بار ها اجرا شه، پس باید بار ها و بار ها هم تفسیر شده و حلقه اجرا-تفسیر تکرار شه.
در عوض کامپایلر دقیقا مزایا و معایب برعکس مفسر رو داره، یعنی اینکه کامپایلر نیاز داره که جلوتر از زمان اجرا (و نه در زمان اجرا) تمامی کد ها رو آماده کنه و در نتیجه این عمل زمانبر خواهد بود. تفاوت دیگه ای که اینجا وجود داره اینه که مفسر باید در زمان اجرا کارشو انجام بده و در نتیجه زمان کافی برای بهینه ترین تبدیل کد منبع کد ماشین رو نداره ولی این برعکس کامپایلر وقت داره که زمان بیشتری صرف فکر کردن و بهینه سازی این فرآیند انجام بده.
وب اسمبلی چیست ؟ | کامپایلرهای JIT
مرورگر ها برای اینکه بتونن از مزایای هر دو نوع اجرا بهره بگیرند، شروع به ترکیب این دو روش کردن و اینطور بود که مانیتور (Monitor) در JS بوجود آمده. مانیتور وظایف داره که روی اتفاقاتی که در مرورگر میفته نظارت کنه، مثلا اینکه یک تابع هر از چند وقت یک با صدا زده میشه. در ابتدا کار که مانیتور هنوز اطلاعاتی جمع نکرده، تمامی کد از مفسر رد میشه، و اگر تابعی به تعداد بالا صدا زده شده، تابه به اصطلاح گرم میشه، و با گرم شدن تابع، مانیتور میفهمه که این تابع باید کامپایل شه. این کار تکه تکه انجام میشه. برای مثال اگر تابه جمع دو متغیر داشته باشیم و در زمان اجرا مشخص شده که هر دو طرف علامت جمع integer هستند، یه نسخه جمع دو عدد integer به عنوان stub کامپایل میشه. همینطور که کد های بیشتری اجرا میشن، Stub های بیشتری هم درست میشن.
حالا اگر کدی از حالت warm خارج شه و بسیار بیشتر از دیگر کد ها اجرا شده، به اصطلاح hot میشه، یعنی اینکه ارزش این رو داره که توسط کامپایلر بهینه سازی شده. ولی فرآیند بهینه سازی نیاز داره که فرضیاتی رو درباره کد شما در نظر بگیره. مثلا اینکه اگه تا به الان ورودی ها به تابع شما همگی از نوع X بودند، پس باید از این به بعد هم همگی از نوع X باشند. ولی در دنیای زبان های Dynamic چنین چیزی برقرار نیست. در نتیجه باید کد اضافه تری برای بررسی ساختار فرض شده اجرا شه. اگز این فرضیات ثابت شده، کد optimize شده اجرا میشه وگرنه این کد دور ریخته میشه و نسخه مفسر و یا کامپایل شده ولی optimize نشده اجرا خواهد شد.
اگر چندین بار یک کد optimize شه و دوباره به اصطلاح de-optimize شه، نسبت به ورژن optimize نشده زمان اضافی خواهد گرفت. در نتیجه monitor این تکه از کد رو با یه برچسب مشخص میکنه که دیگه نیازی به optimize کردن اون نیست. برای ادامه بحثمون نیازه که یه یادآوری از نحوه اجرای کد در سیستم داشته باشیم. میدونیم که وقتی کدی می نویسیم این کد به کد assembly تبدیل میشه. کد اسمبلی کدی هست که کاملا رابطه یک به یک با کد باینری داره که قراره داخل یه معماری خاص از کامپیوتر، اجرا شه. مثلا فرض کنید کدی به زبان C++ نوشتید و قراره روی معماری 64 بیتی Intel تون اجراش کنید. پس این کد به اسمبلی مخصوص این معماری تبدیل خواهد شد. و این اسمبلی به کد صفر و یک نظیرش تبدیل میشه.
حالا اگه بخوایم رابطه بین زبان ها و معمار ها رو مشخص کنیم رابطه n به m میشه، یعنی به ازای هر معماری و زبان برنامه نویسی باید یه اسمبلر نوشته شه. که این کار اصلا بهینه نیست. بهتره که تمامی این زبان ها به یک نوع دیگه از کد تبدیل شن (IR) و بعد بنا به معماری مقصد، کد به اسمبلی تبدیل شه.
حالا وب اسمبلی کجای این قضیه قرار میگیره؟ وقتی IR تولید میشه ما می دونیم که قراره روی کدوم معماری اجرا شه، ولی وقتی در محیط وب هستیم این داده رو نخواهیم داشت. پس باید IR رو به فرمتی تبدیل کنیم که به سرعت بالا امکان تبدیل به Assembly معماری Client و اجرا اون باشه.
در نهایت فرمت ایجاد شده:
- حجم کمتری داره
- عملیات Parsing زمان کمتری خواهد گرفت چرا که خروجی WebAssembly یک bytecode هست و فقط نیاز به decode شدن داره (bytecode همون فرمت میانی بین کد ماشین و کد منبع هست که بعد از تحلیل نگارشی و معنایی کد انجام تولید میشه)
عملیات Compile کمتری انجام میشه، چرا که خیلی از کامپایل ها قبل از اینکه Client درخواستشون کنه آمده برای serve کردن، بارگذاری شدند.
وب اسمبلی چیست ؟ | نتیجه گیری
با کمک توانایی های اضافه شده بوسیله وب اسمبلی به دنیای وب، می توان منتظر انقالب هایی در سمت توسعه اپلیکیشن های Client بوده و شاهد پیش روی قلمرو دنیای وب در قلمرو دنیای اپلیکیشن های سمت دسکتاپ باشیم. با استفاده از این پتتاسیل ها، می توان شاهد تغییرات بزرگی در دهه آتی وب باشیم. حال که با وب اسمبلی چیست و ویژگی های آن آشنا شدید. می توانید از دیگر مقالات سایت Evolearn | ایوولرن دیدن کنید.