ورود ماژولها به دنیای جاوااسکریپت، همه برنامهنویسان را تشویق کرد تا کدهای خود را به صورت بخشهای کوچک و قابلاستفاده مجدد (Reusable) بنویسند. اما یک سوال مهم: آیا هر کد جاوااسکریپتی میتواند در هر محیطی اجرا شود؟
فرض کنید یک ماژول پیدا کردهاید که برای رمزنگاری پسورد کاربران، هشِ SHA تولید میکند. آیا میتوانید از آن هم در فرانتاندِ مرورگر استفاده کنید و هم در سمت سرور (Node.js)؟ پاسخ این است: بستگی دارد!
همانطور که در بخشهای قبلی دیدیم، ماژولها کماکان به متغیرهای جهانی (Globals) دسترسی دارند. همین دسترسی، برگ برنده یا عامل شکست آنهاست:
اگر ماژول شما از متغیری مثل window یا document استفاده کند، در مرورگر مثل ساعت کار میکند اما در Node.js خطای آنی میدهد؛ چون آنجا اصلاً چیزی به نام window وجود ندارد!
به طور مشابه، اگر کد شما برای کار کردن به process.env وابسته باشد، فقط و فقط در محیط Node.js اجرا خواهد شد.
برای حل این مشکل و بالا بردن بازدهی کدها، توصیه میشود کدهای خود را ایزومورفیک (Isomorphic) یا یونیورسال (Universal) بنویسید؛ یعنی کدی که در هر محیطی قرار گرفت، رفتار یکسان و بدون خطایی داشته باشد.
برنامهنویسان حرفهای معمولاً از ۳ روش زیر برای فرامحیطی کردن کدهای خود استفاده میکنند:
کد خود را به دو بخش کاملاً مجزا تقسیم کنید:
بخش هسته (Core): این بخش فقط و فقط شامل منطق خالص جاوااسکریپت (Pure JS Logic) است (مثلاً فرمول ریاضی محاسبه هش). در این بخش به هیچ عنوان نباید به DOM، شبکه یا سیستم فایل (Filesystem) دسترسی داشته باشید.
بخش اتصال (Binding): این بخش که معمولاً بسیار سبک است، وظیفه ارتباط با محیط (Global Context) را دارد.
یک مثال ملموس: پوسته مرورگر (Browser Binding) مقدار پسورد را از یک اینپوت باکس در صفحه وب میخواند، و پوسته سرور (Node Binding) آن را از
process.envدریافت میکند. اما هر دو پوسته، مقدار خوانده شده را به یک تابع هسته واحد میفرستند. با این روش، هسته کد شما در همهجا قابل استفاده است.
قبل از استفاده از هر متغیر جهانی، ابتدا با یک شرط ساده بررسی کنید که آیا آن متغیر در محیط فعلی وجود دارد یا خیر. به این کد هوشمند دقت کنید:
// myModule.js
let password;
if (typeof process !== "undefined") {
// ما در محیط Node.js هستیم؛ پسورد را از پروسس لود کن
password = process.env.PASSWORD;
} else if (typeof window !== "undefined") {
// ما در محیط مرورگر هستیم؛ پسورد را از تگ اینپوت وبسایت بگیر
password = document.getElementById("password").value;
}
نکته جدی: این روش زمانی عالی است که هردو شرط در نهایت به یک رفتار یکسان (ایزومورفیک) ختم شوند. اگر قرار باشد برای هر محیط کدهای عظیمی بنویسید که بخش زیادی از آن در محیط دیگر بلااستفاده بماند، بهتر است از همان روش اول (جداسازی هسته و پوسته) استفاده کنید.
globalThisگاهی اوقات میخواهید از یک قابلیت مدرن وب (مثل تابع fetch) استفاده کنید. این تابع در مرورگرها وجود دارد و در Node.js هم از نسخه ۱۸ به بعد اضافه شده است؛ اما تکلیف نسخههای قدیمیتر Node.js چیست؟
شما میتوانید با استفاده از بارگذاری دینامیک ماژولها، یک پولیفیل (Polyfill) یا کدهای جایگزین را فقط در صورت نیاز لود کنید:
// myModule.js
if (typeof fetch === "undefined") {
// اگر تابع fetch وجود نداشت (مثلاً در Node.js قدیمی)، پکیج node-fetch را لود کن
globalThis.fetch = (await import("node-fetch")).default;
}
// ... از اینجا به بعد با خیال راحت از fetch استفاده کن
globalThis چیست؟در مرورگرها شیء جهانی window است، در Node.js شیء جهانی global است و در ورکرها self! برای اینکه برنامهنویسان گیج نشوند، جاوااسکریپت یک متغیر استاندارد و واحد به نام globalThis معرفی کرده که در تمامی محیطها به شیء جهانی همان محیط اشاره میکند. اگر میخواهید یک متغیر جهانی در ماژول خود بسازید، این ابزار بهترین انتخاب است.
تلاش برای نوشتن کدهای فرامحیطی و مستقل، یکی از بهترین عادتهای یک مهندس نرمافزار است. این کار باعث میشود زحمت شما هدر نرود و دیگران بتوانند در هر پروژهای از کدهای شما لذت ببرند. جالب است بدانید که محیطهای اجرایی مدرن (مثل Node.js، دینو و بان) نیز روزبهروز در حال پیادهسازی ابزارهای استاندارد وب (Web APIs) هستند تا این هماهنگی و یکپارچگی در دنیای جاوااسکریپت به اوج خود برسد.
این محتوا کاملا رایگان توسط تیم کدلپر ترجمه شده و در اختیار شما کاربران عزیز قرار گرفته است، هر گونه کپی برداری برای مقاصد غیر رایگان و بدون ذکر منبع، مورد پیگیری قانونی قرار میگیرد.
ترجمه شده از منبع: https://developer.mozilla.org/en-US/docs/Web/JavaScript