نسخه 26.5.0 Node.js اکنون در دسترس است. این یک نسخه Current است، نه یک شاخه LTS، بنابراین در لبه‌ی پیشروِ قابلیت‌های این پلتفرم قرار دارد. این تفاوت اهمیت دارد. شما نباید آن را کورکورانه در یک محیط عملیاتی (production) که انتظار هجده ماه پایداری را دارد، جایگزین کنید. اما این نسخه‌های کوچک‌تر و سریع‌تر، جایی هستند که آینده در حال شکل‌گیری است. آن‌ها نشان می‌دهند که نگهدارندگان (maintainers) کدام APIها را در حال صیقل دادن هستند و مقصد بعدی runtime کجاست. در نسخه 26.5.0، کار اصلی در Web Streams API انجام شده است، همراه با دو اصلاح هدفمند که Node را به هم‌ترازی با مرورگر (browser parity) نزدیک‌تر می‌کند. این نسخه همچنین دو نقص در لایه‌های مدیریت سیستم فایل (file system) و URL را برطرف می‌کند.

Web Streams در Node.js چه کار می‌کنند؟

اگر برای مدتی کد استریمینگ (streaming) در Node نوشته باشید، می‌دانید که ماژول داخلی stream شخصیت خاص خود را دارد. Readable ،Writable ،Transform و Duplex سال‌هاست که اسب‌های کاری این اکوسیستم بوده‌اند. آن‌ها قدرتمند هستند، اما با استریم‌هایی که در مرورگر با آن‌ها برخورد می‌کنید، یکسان نیستند. وقتی سعی می‌کنید منطق را بین یک service worker در فرانت‌اند و یک route handler در بک‌اند به اشتراک بگذارید، این شکاف تبدیل به اصطکاک می‌شود. در نهایت مجبور می‌شوید آداپتورها را دوباره بنویسید، داده‌ها را به اشکال ناآشنا کپی کنید، یا به سادگی از اشتراک‌گذاری کد خودداری کنید.

Web Streams API برای پر کردن این شکاف وجود دارد. این همان استانداردی است که مدیریت بدنه (body) در fetch مرورگر را قدرت می‌بخشد. با آوردن آن به Node، این پروژه به شما اجازه می‌دهد منطق استریمینگ را یک بار بنویسید و آن را در هر دو محیط اجرا کنید. این API با اشیاء ReadableStream ،WritableStream و TransformStream سروکار دارد که تکه‌ها (chunks) را از طریق یک رابط یکپارچه منتقل می‌کنند. نسخه 26.5.0 آن رابط را بازنویسی نمی‌کند، اما دو پیچ مهم را سفت‌تر می‌کند.

اصلاح releaseLock و پاکسازی BYOB Readers

یکی از تغییرات ملموس در این نسخه، اصلاح متد releaseLock در WritableStreamDefaultWriter است. در مدل Web Streams، یک قفلِ نویسنده (writer lock) از دسترسی همزمان چندین مصرف‌کننده به یک استریم جلوگیری می‌کند. وقتی releaseLock() را فراخوانی می‌کنید، در واقع سیگنال می‌دهید که نویسنده شما کارش تمام شده و استریم زیربنایی برای عملیات بعدی آزاد است. یک پیاده‌سازی ناقص در اینجا می‌تواند استریم را در وضعیت بلاتکلیفی (limbo) رها کند؛ به طوری که استریم همچنان تصور می‌کند تحت مالکیت است، در حالی که نویسنده از بین رفته است. در یک سرور شلوغ که در حال تجزیه (parsing) آپلودها یا انتقال داده‌ها به فضای ذخیره‌سازی است، این نوع قفل‌های قدیمی می‌تواند یک خط لوله (pipeline) را متوقف کند یا خطاهایی ایجاد کند که ردیابی منبع آن‌ها دشوار است. اصلاح انجام شده در نسخه 26.5.0، فرآیند انتقال (handoff) را دوباره قابل پیش‌بینی می‌کند.

دومین تغییر در Web Streams، نحوه کارکرد ReadableStream و TransformStream با خواننده‌های BYOB را بهبود می‌بخشد. BYOB مخفف Bring Your Own Buffer است. به جای اینکه استریم هر بار که داده‌ای را تحویل می‌دهد یک تکه حافظه جدید اختصاص دهد، شما بافری را که از قبل کنار گذاشته‌اید به آن می‌دهید. استریم آن بافر را پر می‌کند، شما بایت‌ها را پردازش می‌کنید و سپس همان بافر را برای استفاده مجدد بازمی‌گردانید. این یک تفاوت مکانیکی کوچک است که هنگام جابجایی حجم عظیمی از داده‌ها، نتایج بسیار بزرگی به همراه دارد.

Node مدتی است که از BYOB پشتیبانی می‌کند، اما حالات مرزی (edge cases) در ReadableStream و TransformStream می‌توانستند هنگام اتصال یک خواننده BYOB دچار مشکل شوند. جزئیات اصلاح کمتر از نتیجه عملی آن اهمیت دارد: استریم‌هایی که از بافرهای صریح استفاده می‌کنند، اکنون در هر دو مرحله خواندن و تبدیل، قابل اعتمادتر هستند. اگر به دلیل خطاهای عجیب در طول رویدادهای backpressure از خواننده‌های BYOB دوری کرده‌اید، این نسخه یک دلیل دیگر برای دوری کردن از آن‌ها از میان برمی‌دارد.

BYOB در واقع کجا کاربرد دارد؟

صحبت کردن درباره بازاستفاده از بافر به صورت انتزاعی آسان است. مفیدتر این است که به جایی فکر کنیم که این موضوع اهمیت پیدا می‌کند.

تصور کنید در حال نوشتن سرویسی هستید که آپلودهای تلمتری (telemetry) را می‌پذیرد. آن آپلودها ممکن است لاگ‌های فشرده یا داده‌های خام سنسور باشند که هر کدام چندین صد مگابایت حجم دارند. اگر استریم برای هر بخش از داده یک Buffer جدید در Node اختصاص دهد، Garbage Collector بیش از حد کار می‌کند و جهش حافظه (memory spikes) به سرعت بالا می‌رود. با یک خواننده BYOB، شما در هنگام شروع برنامه، مجموعه‌ای محدود از بافرها را اختصاص می‌دهید. استریم آن‌ها را پر می‌کند، پارسر شما آن‌ها را تخلیه می‌کند و آن‌ها دوباره به چرخه بازمی‌گردند. میزان مصرف حافظه ثابت می‌ماند. همین الگو زمانی که در حال پروکسی کردن ترافیک شبکه بین دو سوکت هستید یا فایل‌های بزرگ CSV را خط به خط بدون بارگذاری کل آن‌ها در RAM تجزیه می‌کنید، صدق می‌کند.

استریم‌های تبدیل (Transform streams) نیز در اینجا به همان اندازه اهمیت دارند. یک TransformStream در میان یک خط لوله (pipeline) قرار می‌گیرد، که شاید وظیفه‌اش باز کردن فشرده‌سازی یک استریم gzip یا رمزنگاری تکه‌ها (chunks) در لحظه باشد. اگر مرحله تبدیل در مدیریت بافرهای BYOB دچار خطا شود، ممکن است با خروجی‌های خراب‌شده، تکه‌های از دست رفته یا توقف (stall) در زیر بار کاری مواجه شوید. اصلاحات نسخه 26.5.0 دقیقاً به همین نوع اختلالات در خط لوله می‌پردازند، به همین دلیل است که هر کسی که عملیات I/O با توان عملیاتی بالا (high-throughput) انجام می‌دهد، باید به این موضوع توجه کند.

پیروزی‌های بی‌صدا: سیستم فایل و شفافیت خطاها

همه چیز در نسخه 26.5.0 مربوط به استریمینگ نیست. این نسخه همچنین رفتار fs.rm و fs.rmSync را زمانی که گزینه recursive روی false تنظیم شده است، اصلاح می‌کند. پیش از این، ارسال recursive: false در کنار مسیر یک دایرکتوری می‌توانست در هنگام پاکسازی نتایج غیرمنتظره‌ای ایجاد کند. این متد ممکن بود به گونه‌ای عمل کند که با قصد صریح فراخواننده مطابقت نداشته باشد؛ مثلاً بیش از آنچه انتظار می‌رفت حذف کند یا بسته به پلتفرم، به روش‌های ناسازگاری با شکست مواجه شود. پاکسازی فایل‌ها از آن دسته عملیاتی است که باید خسته‌کننده و قابل پیش‌بینی باشد. خسته‌کننده بودن یعنی خوب بودن. این اصلاح، آن قابلیت پیش‌بینی‌پذیری را بازمی‌گرداند، بنابراین اسکریپت‌های پاکسازی دایرکتوری موقت یا منطق تخریب (teardown) استقرار شما دقیقاً همان‌طور که کد نشان می‌دهد عمل می‌کنند.

همچنین یک بهبود در کیفیت تجربه کاربری (quality-of-life) در نحوه گزارش خطا توسط URL.canParse وجود دارد. این متد بررسی می‌کند که آیا یک رشته یک URL معتبر است یا خیر، بدون اینکه در صورت مواجهه با ورودی نامعتبر، خطا (throw) پرتاب کند. در نسخه 26.5.0، اکنون زمانی که مشکلی پیش می‌آید، اطلاعات Error.cause بهتری را همراه دارد. شیء خطا به جای بلعیدن دلیل اصلی، زنجیره علت‌ها را حفظ می‌کند. این بدان معناست که وقتی تجزیه (parse) یک URL در اعماق یک تابع کمکیِ اعتبارسنجی با شکست مواجه می‌شود، استک (stack) ثبت‌شده به شما می‌گوید که آیا مشکل از پروتکل اشتباه بوده، هاست‌نیم (hostname) مفقود بوده یا مشکل ساختاری دیگری وجود داشته است. شما زمان کمتری را صرف پراکنده کردن لاگ‌های دیباگ دستی در تمام نقاط فراخوانی می‌کنید.

آیا باید ارتقا دهید؟

پاسخ بستگی به این دارد که چه چیزی را اجرا می‌کنید.

اگر بارهای کاری تولیدی (production workloads) شما روی یک نسخه LTS مانند سری v20.x قرار دارند، همان‌جا بمانید. این اصلاحات در نهایت به نسخه‌های قدیمی‌تر (backport) منتقل می‌شوند یا در نسخه LTS فعال بعدی عرضه خواهند شد. پایداری و جداول زمانی قابل پیش‌بینیِ پشتیبانی، بر مزیتِ یک قفل استریم کمی روان‌تر یا خطای URL شفاف‌تر در سروری که در حال حاضر به درستی کار می‌کند، برتری دارد.

اگر در حال ساخت یک سرویس جدید، نمونه‌سازی (prototyping) یک خط لوله داده‌های بلادرنگ (real-time) هستید، یا به طور فعال از Web Streams API برای I/Oهای حساس به عملکرد استفاده می‌کنید، ارتقا به نسخه 26.5.0 ارزشش را دارد. همگام‌سازی تدریجی بین استریم‌های Node و Web Streams مرورگرها، صرفاً یک پیروزی در زمینه سازگاری نیست. این شرط‌بندی روی یک محیط اجرای (runtime) یکپارچه‌تر برای JavaScript است که در آن، همان منطق انتقال داده می‌تواند بدون لایه‌های ترجمه، بین سرور و کلاینت جابجا شود. این کار بار شناختی را کاهش داده و سطح بروز باگ‌ها را هنگام ارسال کد توسط تیم شما به هر دو محیط، کمتر می‌کند.

این نسخه کوچک است، اما مسیر مشخص است. Node همچنان در حال سرمایه‌گذاری روی APIهای مبتنی بر استاندارد است که در هر جایی که JavaScript اجرا می‌شود، کار می‌کنند. بهبودهای Web Streams ویژگی‌های خبری (headline features) نیستند، اما مسیری را که سال‌ها ناهموار بوده، هموار می‌کنند. اگر از نسخه Current استفاده می‌کنید، نسخه 26.5.0 را دریافت کنید و منتظر باشید تا این اصلاحات در زمان مناسب به دنیای LTS شما نیز راه یابند.

Source: Dev.to – Node.js 26.5.0: What's New for Web Streams and Error Handling

Join the discussion and keep learning with the GyaanSetu community on Telegram.