goja: موتور جاوااسکریپت خالص Go
خلاصهٔ کاملتر
پروژهٔ goja یه پیادهسازی از ECMAScript 5.1 با زبان Go خالصه که تمرکزش روی سازگاری با استاندارد و کاراییه. تو مستنداتش اومده که این پروژه بهشدت از پروژهٔ otto الهام گرفته، ولی بهطور میانگین ۶ تا ۷ برابر سریعتر از اونه. نکتهٔ اصلیش اینه که چون با Go خالص نوشته شده، هیچ وابستگی cgo نداره، پس ساختش راحته و روی هر پلتفرمی که Go پشتیبانی میکنه اجرا میشه.
از نظر قابلیتها، goja پشتیبانی کامل از ES5.1 (شامل regex و strict mode) داره و تقریباً همهٔ تستهای tc39 رو برای بخشهایی که پیادهسازی شده پاس میکنه. بخش زیادی از قابلیتهای ES6 هم پیاده شده که هنوز در حال کاره. با همین حالا هم میتونه Babel، کامپایلر TypeScript و تقریباً هر چیزی که با ES5 نوشته شده باشه رو اجرا کنه.
اجرای یه قطعه کد و گرفتن نتیجه خیلی سادهست: یه Runtime میسازی و رشتهٔ کد رو بهش میدی.
vm := goja.New()
v, err := vm.RunString("2 + 2")
if err != nil {
panic(err)
}
if num := v.Export().(int64); num != 4 {
panic(num)
}برای رد و بدل کردن داده بین Go و JS هم ابزار داره: هر مقدار Go رو با Runtime.ToValue() میشه به JS پاس داد و هر مقدار JS رو با Value.Export() یا Runtime.ExportTo() به Go برگردوند. حتی میتونی یه تابع JS رو با ExportTo مستقیم به یه تابع Go تبدیل کنی که مثل یه تابع معمولی Go صداش بزنی.
نویسنده چند تا محدودیت رو هم صادقانه توضیح داده. مثلاً بهخاطر محدودیتهای runtime خودِ Go، WeakRef و FinalizationRegistry فعلاً قابل پیادهسازی نیستن و پیادهسازی WeakMap هم ممکنه مصرف حافظه رو بالاتر از انتظار ببره. JSON.parse() هم چون از کتابخونهٔ استاندارد Go استفاده میکنه، جفتهای surrogate خرابِ UTF-16 رو درست پارس نمیکنه.
یه نکتهٔ مهم دیگه اینه که goja امن برای goroutine نیست؛ هر نمونهٔ goja.Runtime رو فقط یه goroutine در هر لحظه میتونه استفاده کنه. تابعهایی مثل setTimeout() و setInterval() هم چون جزو استاندارد ECMAScript نیستن، اینجا وجود ندارن و باید خودِ برنامهٔ میزبان محیط اجرای همزمان رو کنترل کنه؛ برای همین یه پروژهٔ جدا به اسم goja_nodejs هست که یه event loop و بخشی از قابلیتهای NodeJS رو فراهم میکنه.
نکات کلیدی:
- goja یه موتور ECMAScript 5.1 با زبان Go خالصه، بدون هیچ وابستگی cgo
- بهطور میانگین ۶ تا ۷ برابر سریعتر از otto هست، ولی جایگزین V8 نیست
- میتونه Babel، کامپایلر TypeScript و کدهای ES5 رو اجرا کنه
- امن برای goroutine نیست؛ هر Runtime فقط توسط یه goroutine در هر لحظه
- WeakRef و FinalizationRegistry بهخاطر محدودیت runtime خودِ Go پیاده نشدن




