Node Master
1.02K subscribers
24 photos
2 files
156 links
Group Chat: @nodemastergp
Admin: @napoleon_n1
Download Telegram
امروز یک برنامه کلاسیک HelloWorld با استفاده از #webassembly module مینویسیم و import در #NodeJS صحبت میکنیم برای خودم خیلی باحال بود و تصور این که چه قدرتی این کار داره واقعا جذابه.
این که #NodeJS کند هست همه قبول داریم ولی خب اونقدری کند نیست که بگیم بد هست. حتی روی scale بزرگ هم جواب میده و مشکلی نیست ولی گاهی شاید بخواهیم قدرتش رو با ابزار های کمکی بیشتر کنیم. یکی از این راها استفاده از C++ N-API هست که میشه native module هایی که با CPP توسعه داده شدن رو استفاده کنیم و اصن کلا کل nodejs همین هست. تازگی ها api اومده که میتونیم کد های #rust هم bind کنیم که اسمش رو یادم نمیاد. معمولا این کارا رو زمانی انجام میدن که یک پروژه بزرگ روی nodejs هست و هزینه بازنویسی روی زبان های سریعتر مثل golang خیلی زیاد هست و ارزش نداره و با استفاده از این تکنیک ها قدرتش رو بیشتر میکنن. ( این که golang سریعتره دلیل بر بهتر بودن لزوما نیست ) از این موضوع بگذریم و بریم سر وقت مثال و کد.

اگر از #ESM استفاده میکنید قبلا بهتون گفته بودم که چطور json رو مستقیم import کنید بدون استفاده از fs.readfile و ... . یکی دیگه از ویژگی های #ESM قابلیت import کردن #WASM ماژول ها هست. WASM ها ماژول های نوشته شده با webassambly هست که سرعت near native داره که مقدمه کوچیکی بالا گفتم حالا بریم یکم مثال بزنیم. وقتی راجع به سرعت near native صحبت میکنیم شوخی نیست!
کلا با استفاده از تکنولوژی های زیادی میشه خروچی wasm گرفت از cpp و rust گرفته تا #AssamblyScript که یکچیز شبیه به #TypeScript هست ولی در اینجا ما از فرمتی به اسم #WAT یا که میشه WebAssambly Text Format استفاده میکنیم برای برنامه HelloWorld. حالا بریم با مثال صحبت کنیم.
(module
(memory 1)

(export "memory" (memory 0))
(data (i32.const 0) "Hello, World!\n\00")
(func (export "getTextOffset") (result i32)
i32.const 14
return
)
)

جدا از syntax یکی از بزرگترین چالش هایی که اینجا داریم Memory management هست که در خام ترین حالت ممکن هست تقریبا و اصلا نمیشه اینجا کوچک ترین اشاره به جزیاتش کرد ولی خب خط اول (memory 1) به مقدار 64Kib یعنی 65536 حافظه خطی در اختیار شما قرار میده. (چالش اصلی همین خطی بودن حافظه و manage کردنش برای دیتا های دیگس.
حالا با استفاده از export memory خط بعد این قسمت از حافظه رو که از WebAssembly.Memory برای دسترسی در کد #nodejs میایم و export میکنیم.
بعد با استفاده از data روی خونه اول حافظه شروع میکنیم به نوشتن بایت های helloworld و مهمترین و جذاب ترین قسمتش که کنجکاوی به وجود میاره استفاده از "\00". اینجا میخوام یک سوال مطرح کنم برام توی کامنت بگید که چرا از "\00" استفاده شده ؟
بعد میایم یک فانکشن تعریف میکنیم که یک عدد i32 برمیگردونیم که آدرس اخرین خونه ای هست که hello world داخلش قرار داره یعنی از 0 شروع شده تا 14.
حالا باید این رو compile کنیم به wasm که ابزار های مختلف هست. میتونید این کد رو کپی کنید و از سایت https://webassembly.github.io/wabt/demo/wat2wasm/ استفاده کنید برای تست و خروجی wasm رو بگیرید.
حالا آمده ایم بریم برای بخش node.
import * as mywasm from "./mywasm.wasm";

const buf = Buffer.from(mywasm.memory.buffer);

const helloWorld = buf.subarray(0, mywasm.getTextOffset());

console.log(helloWorld.toString("utf-8"));

ماژول کامپایل شده رو import میکنیم و دوتا export در کد wat میبینید. یکی memory که حافظه خام ما هست که تبدیل میکنیم به buffer ( بدون تبدیل هم میشد این کارا رو کرد ولی حال نداشتم :) )
بعد این buf ما 64kib هست درصورتی که ما فقط 14 byte از این رو میخوایم. با استفاده از export دوم یعنی فانکشن getTextOffset میایم این buf رو قیچی میکنیم و 14 byte که حاوی helloworld ما هست میگیریم و بعد با encode کردن به utf8 لاگ میگریم و تمام. حالا برای ران کردن میتونید این کار کنید.
node --experimental-wasm-modules main.js


دوستان توجه کنیدکه خیلی خیلی خلاصه کردم از اتفاق هایی که میوفته تا کوتاه بشه ولی زیر به صورت تیتر وار میگم.
- اول درمورد memory این که حالا برنامه ما اینجا کوچیک بود و زیاد مهم نیست ولی این که 64kib مموری بگیری و از 14 byte فقط استفاده کنی اصلا کار درستی نیست.
- دوم کلا حواسمون باید خیلی به encode شدن باید باشه
- سوم همون سوالی که بالا گفتم بهش فکر کنید
- چهارم اون خط تبدیل کردن به buffer نیاز نیست و راه های بهتری هست که وقت نداشتم برم دنبالشون و هدف فقط اشاره به این تکنولوژی بود.
👍6