<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های مهران فریدونی</title>
        <link>https://virgool.io/feed/@m_22252359</link>
        <description></description>
        <language>fa</language>
        <pubDate>2026-06-07 14:30:53</pubDate>
        <image>
            <url>https://static.virgool.io/images/default-avatar.jpg</url>
            <title>مهران فریدونی</title>
            <link>https://virgool.io/@m_22252359</link>
        </image>

                    <item>
                <title>روشی بهتر برای به اشتراک گذاشتن کد بین پروژه‌های Nodejs</title>
                <link>https://virgool.io/@m_22252359/%D8%B1%D9%88%D8%B4%DB%8C-%D8%A8%D9%87%D8%AA%D8%B1-%D8%A8%D8%B1%D8%A7%DB%8C-%D8%A8%D9%87-%D8%A7%D8%B4%D8%AA%D8%B1%D8%A7%DA%A9-%DA%AF%D8%B0%D8%A7%D8%B4%D8%AA%D9%86-%DA%A9%D8%AF-%D8%A8%DB%8C%D9%86-%D9%BE%D8%B1%D9%88%DA%98%D9%87-%D9%87%D8%A7%DB%8C-nodejs-bap8mymxv7uy</link>
                <description>به اشتراک گذاشتن کد بین پروژههای Nodejsدر این مقاله پی خواهید برد که چرا ماژولهای کد را تاکنون به سختی به اشتراک میگذاشتید. همه ما میدانیم که چگونه ورودی و خروجی ناهمزمان Node آن را به یکی از ابزارهای واقعی برای توسعه خدمات تبدیل کرده است (به طور معمول REST APIها). اگر روی پروژههای متوسط   یا بزرگ کار کرده باشید، احتمالا روند تقسیم عملکرد بین سرویسهای منفرد را تجربه کردهاید.این روش برای کمک به گره نخوردن کد بسیار عالی است، همچنین برای استقرارهای جزئی و کاهش خطرات خرابی فاجعه بار هنگام به روزرسانی کدهای قدیمی بسیار خارق العاده است (زیرا میزان خسارتی که شما میتوانید وارد کنید محدود به یک سرویس خاص است).همانطور که گفته شد اگر موارد فوق را تجربه کرده باشید، احتمالا با این مسئله مواجه شدهاید که یک سری کتابخانههای سفارشی داخلی داشته باشید که باید بین سرویسهای مختلف پروژه به اشتراک گذاشته شود. به عنوان مثال: فایل ورود به سیستمی که نوشتید یا آن کتابخانه ارتباطی که برای ارسال داده بین سرویسها نوشتید.در هر صورت اجبار برای به اشتراک گذاشتن کد مشترک بین ماژولهای یک پروژه نیاز به برخی از تدارکات دارد، زیرا آنچه شما انجام نمیدهید این است که سه نسخه مختلف از همان کد را به طور موازی در داخل سه ماژول مختلف نگه دارید. این بدترین سناریو خواهد بود و میتوانید به راحتی از آن اجتناب کنید.راههای موجود برای حل این مشکلمن مطمئنم که هرکسی میتواند روشهای جایگزینی برای حل این مشکل پیدا کند، اما دو روش بسیار معمول برای انجام آن در زیر ذکر میکنم:شماره 1: اشتراک کد در NPMمطمئنا میتوانید به منظور تهیه یک پروژه جداگانه برای کد مشترک خود وقت گذاشته و آن را در NPM به اشتراک بگذارید. در نگاه اول این ممکن است ایده خوبی به نظر برسد و یک راه حل عالی باشد، در هر صورت با شرح وظایف NPM متناسب است، نه؟با این حال اگر از دیدگاه یک قطعه کد بسیار کوچک نسبت به یک پایگاه کد بزرگتر به آن نگاه کنیم، شما نیاز دارید که آن را با دیگران تقسیم کنید، چند دلیل وجود دارد که چرا این یک روش مشکلساز است. اجازه بدهید بیشتر توضیح بدهم:    ممکن است از یک رجیستری خصوصی استفاده نکنید. به هر حال شما کد سفارشی خود را با سایر همکارانی که در حال توسعه سرویسهای دیگر پروژه هستند به اشتراک میگذارید، و نمیخواهید دیگران در سراسر جهان از کد شما استفاده کنند (حتی کد را مشاهده کنند، چرا که میتواند حاوی محتوای خصوصی باشد که باید مخفی بماند). همانطور که احتمالا میدانید، NPM به شما امکان میدهد از ریپازیتوریهای خصوصی استفاده کنید، جایی که میتوانید کد سفارشی خود را بدون انتشار آن به صورت عمومی منتشر کنید. تنظیم یک مورد به زمان و منابع نیاز دارد، بنابراین حتی اگر این یک راه حل برای آن باشد، اگر فقط چند کتابخانه سفارشی داشته باشید که بخواهید آنها را در میان ماژولها به اشتراک بگذارید، مقرون به صرفه نخواهد بود.    حتی اگر نکته قبلی برای شما مشکلی ایجاد نکرد، مجبور به استخراج کد در یک پروژه جداگانه و سپس ایجاد و انتشار ماژولها هستید. توجه داشته باشید که به اشتراک گذاشتن ماژولها زیاد پیچیده نیست، اما به فاکتورگیری مجدد نیاز دارد. مهم نیست که چه قدر بزرگ باشد یا برای این کار وقت یا نیروی انسانی نداشته باشید.    کدی که استخراج کردهاید دیگر در دسترس شما نیست. بله این در داخل پوشه node_modules است، جایی که تعداد بسیار کمی از توسعه دهندگان جرات ورود به آن را دارند (یا حتی نمیدانند کجا را جستجو کنند). نکته در اینجا این است که شما به معنای واقعی کلمه کد را از پایگاه کد خود حذف کرده و آن را به یک موجودیت عمومی و خارجی تبدیل کردهاید. این اساسا نگهداری را دشوارتر میکند، زیرا اکنون یک پروژه جدید با پایگاه کد خاص خود است. این تنها درصورتی است که در مورد یک کتابخانه صحبت کنیم، اگر سه کتابخانه استخراج کنید چه میشود؟ یا حتی بیشتر؟ چه کسی آن را نگهداری میکند و چه زمانی آنها را به روزرسانی میکنند؟اگرچه در نگاه اول این راه حل میتواند قابل قبول به نظر برسد، اما برای طولانی مدت میتواند دست و پا گیر و ناجور شود.شماره 2: استفاده از GITدو روش وجود دارد که گیت به طور بالقوه میتواند در اینجا به شما کمک کند ( شاید سیستمهای کنترل نسخه دیگر نیز همین کار را انجام دهند، اما من خیلی با آنها آشنا نیستم. بنابراین به آنچه میدانم پایبند خواهم ماند):    انتقال کد عمومی به یک ریپازیتوری متفاوت، اساسا کاری مشابه آنچه با NPM انجام دادهاید انجام میشود. اما اکنون باید زیرماژولها را در دایرکتوری خود داشته باشید. این یک راه حل عالی است که گیت برای حل مشکلی که در مورد آن صحبت میکنیم ارائه میدهد، اما بگذارید صادقانه بگوییم این ابزار برای بسیاری از توسعه دهندگان بیش از حد شلوغ است و نیازی به اضافه کردن پیچیدگی بیشتر در رابطه با این رویکرد ندارد.    به جای افزودن ریپازیتوری جدید، میتوانید همه چیز را به صورت انحصاری در بیاورید. بنابراین به جای اینکه سرویسها و ماژولهای خود را به ریپازیتوریهای جداگانه تقسیم کنید، یک مورد ایجاد کرده و همه چیز را به آن اضافه میکنید. بسته به نوع تنظیمات میتواند ایده خوبی برای شما باشد، در هر صورت به آن فکر کنید. برای داشتن همه چیز در یک ریپازیتوری واحد، ارکستراسیون باید به طرز شگفت انگیزی اجرا شود. به من اعتماد کنید، من این کار را قبلا انجام دادهام، واقعا قابل اجرا است، اما فقط آن را به عنوان آخرین راه حل توصیه میکنم.فعلا اجازه دهید گیت را از تصویر خارج کنیم، یا حداقل بگذارید آن را از راه حل بیرون بگذاریم. اگر هم قبلا برای شما کار کرده است، کاری با آن نداریم.Bit: روشی جدید برای به اشتراک گذاشتن کامپوننتهاBit سرویس جدیدی است که به شما امکان میدهد کامپوننتها را بین پروژههایتان به اشتراک بگذارید. این در نگاه اول بسیار شبیه NPM است.مفهوم کامپوننتها اساسا هر چیزی است که میخواهید به اشتراک بگذارید، چه یک فایل واحد با تعریف کلاس و چه مجموعهای از توابع یا یک پوشه کامل پر از کتابخانههای عمومی. روی هر پروژهای که کار میکنید و ناگهان متوجه شدید قابل اشتراک گذاری است، میتوانید آن را اکسپورت کنید. پس چه تفاوتی با NPM وجود دارد؟    اگر مبتدی هستید، دیگر کد را از پایگاه کد خود حذف نمیکنید. من این را یک مزیت بزرگ میدانم، زیرا شما بدون نیاز به جدا کردن از بقیه پروژه با محتوای به اشتراک گذاشته شده سروکار دارید. همچنان نگهدارنده آن هستید، چرا که بالاخره آن را ایجاد کردهاید، اما درعین حال میتوانید آن را به عنوان یک ماژول npm به اشتراک بگذارید (در عرض یک ثانیه به شما نشان خواهم داد).    کد مشترک شما (مهم نیست که چند کامپوننت مختلف را به اشتراک میگذارید) در مخزن کد باقی میماند. به علاوه برای اینکه بخشی از آن به اشتراک گذاشته شود، لازم نیست ارکستراسیون اضافی به راه حل نسخه سازی کد خود اضافه کنید. اگر باید مرتبا آن را به روزرسانی کنید، فقط کد را به روز میکنید و از ابزار CLI آخرین نسخه از پروژه مقصد را میگیرید.    برخلافNPM ، Bit درخت وابستگی کامپوننت شما را بررسی میکند. به این معنی که اگر فقط یک فایل را به اشتراک بگذارید، اما به سایر فایلهای محلی به عنوان وابستگی نیاز دارید، بیت به شما میگوید و به شما امکان میدهد آنها را به عنوان بخشی از کامپوننت اضافه کنید.اساسا Bit به شما امکان میدهد با رویکردی مشابه با شماره 1 مشکل را حل کنید، همچنین منابعی را برای شما فراهم میکند تا آن را درست انجام دهید:    رجیستری خصوصی توسط Bit ارائه میشود، بنابراین لازم نیست نگران آن قسمت باشید.    برای انتشار نیازی به تنظیم ماژول npm جدید ندارید، فقط با چند مرحله میتوانید بدون نیاز به انجام هر نوع بازسازی مجدد، کد را به اشتراک بگذارید.    کد را از پروژه اصلی که در آن منشا گرفته استخراج نمیکنید. بلکه در همان مکان و در داخل همان ریپازیتوری باقی میماند و تأثیر آن بر روی پروژه تقریبا هیچ است.استفاده از Bit برای به اشتراک گذاشتن کامپوننتهاچگونه کد خود را به اشتراک بگذاریم؟ آنها مستندات بسیار دقیقی دارند که در آن میتوانید جزئیات بیشتری را بررسی کنید، اما برای سادگی به شما نشان میدهم که چگونه سریعا یک کامپوننت را از یک پروژه به پروژه دیگر به اشتراک بگذارید.کامپوننتی که میخواهیم به اشتراک بگذاریم یک شی logger است که نمونهای از Winston میباشد:const winston = require(&quot;winston&quot;)const config = require(&quot;../config.json&quot;)const logger = winston.createLogger({  level: &#x27;info&#x27;,  format: winston.format.json(),  transports: [    new winston.transports.File&#40;{ filename: config.logging.output_files.error, level: &#x27;error&#x27; }&#41;  ]});if (process.env.NODE_ENV !== &#x27;production&#x27;) {  logger.add(new winston.transports.Console({    format: winston.format.simple()  }));}module.exports = loggerگام اول: Bit را نصب کنیدمیتوانید آن را به روشهای مختلف نصب کنید، اما سادهترین و عمومیترین استفاده از npm است:$ npm install bit-bin --globalگام دوم: ورود به سیستمپس از نصب باید وارد شوید یا ثبت نام کنید. انجام این کار بسیار ساده است، به خصوص اگر قبلا یک حساب Github داشته باشید. از خط فرمان فقط کافی است تایپ کنید:$ bit loginاین دستور مرورگر شما را راه اندازی کرده و صفحه ورود به سیستم Bit را باز میکند. پس از ورود به آنجا و انجام اقدامات ثبت نام / ورود به سیستم میتوانید تنظیم کنید که چه مواردی را به اشتراک بگذارید.همچنین توجه داشته باشید که با ورود به سیستم، دامنه جدیدی را به فایل پیکربندی NPM اضافه میکنید. اکنون به دامنه bit دسترسی خواهید داشت که به شما امکان میدهد کامپوننتهای سازنده را مانند ماژولهای کلاسیک NPM نصب کنید.گام سوم: مقداردهی اولیه Workspaceبیت از مفهوم workspace برای گروه بندی مجموعهها (گروهی از کامپوننتها هستند) استفاده میکند. اولین کاری که باید انجام دهید این است که فضای کاری خود را مقداردهی کنید و میتوانید این کار را به سادگی انجام دهید:$ bit initپس از اتمام این میتوانید تصمیم بگیرید که چه چیزی را به اشتراک بگذارید.گام چهارم: یک کامپایلر را پیکربندی کنیدBit کامپایلرهای از پیش پیکربندی شده مختلفی را برای کامپوننت های تحت مدیریت فضای کاری ارائه میدهد. ما از Babel compiler component استفاده خواهیم کرد. این به ما امکان میدهد بدون تکیه بر تنظیمات خاصی در محیط، کدی قابل توزیع برای کامپوننت &quot;logger&quot; خود ایجاد کنیم.کامپوننت ما به لطف کامپایلر Babel استاندارد شده در جاهای دیگر به راحتی توسط دیگران قابل نگهداری است.$ bit import bit.envs/compilers/babel --compilerگام پنجم: افزودن فایل و بررسی وضعیت کامپوننتهاافزودن فایلهایی که میخواهید به اشتراک بگذارید کاملا ساده است. با فرض یک ساختار پروژه مانند موارد زیر:برای اضافه کردن فایلها میتوانید به سادگی آن را انجام دهید:$ bit add lib/logger.jsاین دستور فایل را اضافه کرده و یک کامپوننت جدید به نام &quot;logger&quot; ایجاد میکند. به طور پیش فرض دستور add با استفاده از نام فایل، کامپوننت را نام گذاری میکند. همچنین میتوانید مستندات کامل آن را بررسی کنید تا همه کارهایی که میتوانید با آن انجام دهید را مشاهده کنید.اکنون میتوانید وضعیت را بررسی کنید تا بفهمید که آیا همه موارد مورد نیاز خود را دارید:$ bit statusتصویر بالا خروجی بررسیهای انجام شده توسط Bit را به شما نشان میدهد. اینجاست که CLI درخت وابستگی ماژول ما را ایجاد و بررسی میکند. اگر از قبل به کد نگاه کنید، متوجه خواهید شد که من به یک فایل JSON احتیاج دارم که هنوز اضافه نکردهام. این یکی از مزایای استفاده از Bit به جای npm است، چرا که میتوانیم از دست دادن فایلهای مهم جلوگیری کنیم.پس از افزودن فایل دیگر میتوانید وضعیت جدیدی را بررسی کنید و پاسخ ظاهری بهتری خواهید گرفت.گام ششم: نسخه بندیقبل از بارگذاری فایلها باید نسخه کامپوننت را مشخص کنید. بنابراین یک روش عالی برای مقادیر اولیه همه آنها به طور همزمان است:$ bit tag --all 0.0.1 --message &quot;initial version for the component&quot;این مرحله اجباری است و تا زمانی که نسخه اول را تگ نکنید، قادر به کامیت کردن چیز دیگری نخواهید بود.گام هفتم: اکسپورت کردن کامپوننتوقتی همه موارد بالا آماده شد، برای اکسپورت کامپوننتهای سازنده لازم است مجموعهای را که قرار است در آن جای بگیرند، ایجاد کنید. شما این کار را از وبسایت آنها انجام میدهید و پس از ایجاد آن میتوانید دستور زیر را اجرا کنید:$ bit export &lt;account-name&gt;.&lt;collection-name&gt;من مجموعه را &quot;custom-logger&quot; نامیدم و نام حساب من &quot;deleteman&quot; است، بنابراین دستور من اینگونه خواهد بود:$ bit export deleteman.custom-loggerبا این کار فایل بدون اینکه کاری برای کد شما و یا ریپازیتوری شما انجام شود، در رجیستری سفارشی بارگذاری میگردد.گام هشتم: استفاده از آن در مکان دیگر (اختیاری)اگر لازم باشد از کامپوننت خود در پروژه دیگری استفاده کنید، چه کار میکنید؟ میتوانید از دستور زیر استفاده کنید:$ npm install @bit/&lt;account-name&gt;.&lt;collection-name&gt;.&lt;component-name&gt;بنابراین برای من اینگونه خواهد بود:$ npm install @bit/deleteman.custom-logger.loggerاگر من به یکی از کامپوننتها مراجعه کنم، همه وابستگیها نیز نصب میشوند. بنابراین برای استفاده از آن، فقط کافی است به این صورت عمل کنید:const logger = require(&quot;@bit/deleteman.custom-logger.logger&quot;)logger.info(&quot;Testing test!&quot;)جمع بندیبا استفاده از این مراحل ساده، شما موفق شدهاید کدی را از پروژه خود به اشتراک بگذارید، بدون اینکه مجبور شوید آن را استخراج کنید.به خاطر اینکه مقاله زیاد طولانی نشود، تصمیم گرفتم مراحل اضافی را کنار بگذارم (مانند اینکه چگونه تعامل بین Git و Bit نشان داده میشود، یا اینکه چگونه محتوای یک کامپوننت و نسخه آن را به روز کنید). در پشت این مراحل اساسی چیزهای بیشتری وجود دارد، اما امیدوارم این کافی بوده باشد تا مزایای استفاده از چنین خدماتی را برای به اشتراک گذاشتن کد بین پروژههای مرتبط با حداقل تلاش به شما نشان دهد.اگر قبلا از Bit استفاده کردهاید یا اگر با رویکرد دیگری توانستهاید این مشکل را حل کنید، نظرات خود را در زیر بنویسید.</description>
                <category>مهران فریدونی</category>
                <author>مهران فریدونی</author>
                <pubDate>Tue, 06 Aug 2024 10:46:59 +0330</pubDate>
            </item>
                    <item>
                <title>مقدمه‌ای بر Node.js‌</title>
                <link>https://virgool.io/@m_22252359/%D9%85%D9%82%D8%AF%D9%85%D9%87-%D8%A7%DB%8C-%D8%A8%D8%B1-nodejs-drvjxe5a4cfk</link>
                <description>همه میدانند که Node.js یک runtime متن باز و میان پلتفرمی برای JavaScript است. اکثر توسعه دهندگان Node.js میدانند که این runtime بر پایه V8، یک موتور JavaScript و libuv، یک کتابخانه C چند پلتفرمی ساخته شده است که پشتیبانی I / O ناهمگام را بر پایه حلقههای رویداد فراهم میکند. اما تعداد کمی از توسعه دهندگان میتوانند نحوه کار Node.js به صورت داخلی و نحوه تاثیر گذاشتن بر روی کد آنها را به وضوح توضیح دهند. پس آنها اغلب شروع به یادگیری Node با Express.js، Sequelize، Mongoose، Socket.io و برخی کتابخانههای شناخته شده دیگر میکنند، بدون این که وقت خود را بر روی یادگیری خود Node.js و APIهای استانداردش سرمایه گذاری کنند. به نظر من این یک انتخاب اشتباه است؛ زیرا درک رانش Node.js و دانستن مشخصات APIهای داخلی آن میتواند در جلوگیری از اشتباهات رایج کمک کند.این پست مقدمهای بر Node.js را به شیوهای فشرده، اما همه جنبه به شما میدهد. ما یک بررسی اجمالی بر روی معماری Node.js خواهیم داشت. در نتیجه، سعی خواهیم کرد که برخی دستور العملها را برای ساخت یک وباپلیکیشن سمت سرور با کارایی بالاتر و امنیت بیشتر با Node.js تعیین کنیم. این دستور العملها باید برای تازه کاران Node.js، و همچنین توسعه دهندگان با تجربه کاربردی باشند.بلوکهای ساخت اصلیهر برنامه Node.js بر پایه این کامپوننتها ساخته شده است:    V8 - موتور JavaScript متن باز، با کارایی بالاتر ساخته Google، که در C++ نوشته شده است. این موتور همچنین در مروگر Google Chrome و برخی موارد دیگر هم استفاده شده است. Node.js موتور V8 را از طریق اِیپیآی V8 C++ کنترل میکند.    libuv - یک کتابخانه پشتیبانی چند پلتفرمی با تمرکز بر روی I / O ناهمگام، نوشته شده در C. این کتابخانه در درجه اول برای استفاده شدن توسط Node.js توسعه داده شده بود، اما همچنین توسط Luvit، Julia، pyuv و برخی موارد دیگر هم استفاده میشود. Node.js از libuv برای چکیدهسازی عملیاتهای I / O غیر مسدود کننده، به یک رابط یکپارچه در میان تمام پلتفرمهای پشتیبانی شده استفاده میکند. این کتابخانه مکانیزمهایی را برای مدیریت سیستم فایل، DNS، شبکه، پردازشهای فرزند، لولهکشیها، مدیریت سیگنال، polling و streaming فراهم میکند. libuv همچنین شامل یک thread pool میباشد که با نام Worker Pool شناخته میشود. Worker Pool برای تخلیه کارهایی که نمیتوانند به صورت ناهمگام در سطح سیستم عامل انجام شوند، به کار میرود.    کامپوننتهای متن باز و سطح پایین دیگر، که اغلب در C / C++ نوشته شدهاند:    - c-ares - یک کتابخانه C برای درخواستهای DNS ناهمگام، که برای برخی درخواستهای DNS در Node.js استفاده میشود.    - http-parser - یک کتابخانه parse کننده درخواست / پاسخ HTTP سبک.    - OpenSSL - یک کتابخانه رمزنگاری چند منظوره به خوبی شناخته شده. این کتابخانه در ماژولهای tls و crypto استفاده شده است.    - zlib - یک کتابخانه فشردهسازی داده بدون اتلاف. این کتابخانه در ماژول zlib هم استفاده شده است.    برنامه - کد برنامه شما، و ماژولهای استاندارد Node.js که در JavaScript نوشته شدهاند.    اتصالهای C / C++ - wrapperهایی برای کتابخانههای C / C++ که با استفاده از N-API، یک اِیپیآی C یا برخی APIهای دیگر مربوط به اتصالات برای ایجاد افزونههای Node.js بومی ساخته شدهاند.    برخی ابزار bundle شده که در زیرساختهای Node.js استفاده شدهاند:    - npm - یک ابزار مدیریت پکیج (و اکوسیستم) به خوبی شناخته شده.    - gyp - یک مولد پروژه بر پایه پایتون که از V8 کپی شده است. این مولد توسط node-gyp، یک ابزار خط دستوری میان پلتفرمی برای کمپایل کردن ماژولهای افزونه بومی که در Node.js نوشته شده است، مورد استفاده قرار گرفته میباشد.    - gtest - چارچوب آزمایش C++ مختص Google. این چارچوب برای آزمایش کد بومی استفاده میشود.در اینجا یک نمودار را مشاهده مینمایید که کامپوننتهای اصلی Node.js که در لیست به آنها اشاره شد را نشان میدهد:Runtime نود جِیاِسدر اینجا یک نمودار را مشاهده مینمایید که نحوه اجرای کد JavaScript شما توسط رانش Node.js را نشان میدهد:این نمودار تمام جزئیاتی که در Node.js اتفاق میافتند را نشان نمیدهد، اما مهمترین موارد را برجسته میکند. ما به طور خلاصه آنها را مورد بحث قرار خواهیم داد.وقتی که در ابتدا برنامه Node.js شما شروع میشود، فاز اولیه را به پایان رسانده، یا به عبارتی اسکریپت شروع که شامل ماژولها و ثبت callbackها برای رویدادها میباشد را اجرا میکند. سپس برنامه به حلقه رویداد (که با نامهای «main thread» و «event thread» هم شناخته میشود) وارد میشود، که از نظر مفهومی برای پاسخ دادن به درخواستهای کلاینت ورودی با اجرای callbackهای JavaScript مناسب ساخته شده است. Callbackهای JavaScript به صورت همگام اجرا میشوند، و ممکن است از APIهای Node برای ثبت درخواستهای ناهمگام استفاده کنند، تا پس از اتمام callback به پردازش ادامه دهند. از اینگونه APIهای Node میتوان به تایمرهای مختلف (setTimeout&#40;&#41;، setInterval&#40;&#41; و...)، توابع fs و http و... اشاره کرد. تمام این APIها نیازمند یک callback هستند که وقتی که عملیات مورد نظر به اتمام میرسد، اجرا خواهد شد.حلقه رویداد، یک حلقه تک thread و نیمه بی نهایت بر پایه libuv است. علت این که این حلقه «نیمه بی نهایت» نام دارد، این است که در نهایت در جایی که دیگر کاری برای انجام دادن وجود ندارد، دست از کار میکشد. از دید یک توسعه دهنده، این زمانی است که برنامه شما خارج (exit) میشود.حلقه رویداد بسیار پیچیده است. این حلقه دستکاریهایی را با صفهای رویداد تصور میکند و شامل چند فاز میباشد:    فاز تایمرها - این فاز callbackهای برنامهریزی شده وسط setTimeout&#40;&#41; و setInterval&#40;&#41; را اجرا میکند.    فاز callbackهای در انتظار - callbackهای I / O تعطیل شده تا تکرار حلقه بعدی را اجرا میکند.    فازهای بیکاری و آمادهسازی - فازهای داخلی.    فاز poll - شامل این موارد میشود: دریافت رویدادهای I / O جدید؛ اجرای callbackهای مربوط به I / O (تقریبا تمام آنها، به استثنای close، تایمرها و setImmediate&#40;&#41;)؛ Node.js در زمان مناسب، در اینجا مسدود خواهد شد.    فاز بررسی - callbackهای setImmediate&#40;&#41; در اینجا فراخوانی میشوند.    فاز بستن callbackها - در اینجا برخی callbackهای close اجرا میشوند؛ برای مثال socket.on(‘close’, …).در طی فاز poll، حلقه رویداد با استفاده از چکیدهسازیهای libuv برای مکانیزمهای I / O مختص سیستم عامل polling، درخواستهای غیر مسدود کننده و ناهمگام را برآورده میکند. این مکانیزمهای مختص سیستم عامل، برابر با epoll برای لینوکس، IOCP برای ویندوز، kqueue برای BSD و MacOS و event ports در Solaris هستند.این که Node.js در واقع تک thread است، یک افسانه رایج میان مردم میباشد. اساسا این مسئله حقیقت دارد (یا با توجه به این که یک پشتیبانی آزمایشی برای workerهای وب، که با نام Worker Thread شناخته میشود وجود دارد، قبلا حقیقا داشت)؛ زیرا کد JavaScript شما همیشه بر روی یک thread داخل حلقه رویداد اجرا میشود. اما شما همچنین ممکن است متوجه Worker Pool شوید، که در واقع یک thread pool با اندازه ثابت بر روی نمودار میباشد. پس هر پردازش Node.js چند thread دارد که به موازات هم اجرا میشوند. علت آن این است که تمام عملیاتهای Node میتوانند به روشی غیر مسدود کننده بر روی تمام سیستم عاملهای پشتیبانی نشده اجرا شوند. یک علت دیگر هم برای داشتن Worker Pool این است که حلقه رویداد برای محاسبات حساس به CPU مناسب نیست.پس Node.js (یا به خصوص libuv) تمام تلاش خود را میکند تا API ناهمگام و رانده شده توسط رویداد مشابه برای عملیاتهای مسدود کننده این چنینی را نگه دارد و این عملیاتها را بر روی یک thread pool جداگانه اجرا میکند. در اینجا مثالهایی از عملیاتهای مسدود کننده این چنینی، در ماژولهای داخلی را مشاهده مینمایید:    I/O-bound:    - برخی عملیاتهای DNS در ماژول dns: dns.lookup() و dns.lookupService().    - اکثر عملیاتهای سیستم فایل که توسط ماژول fs فراهم شدهاند؛ مانند fs.readFile&#40;&#41;.    CPU-bound:    - برخی عملیاتهای رمزنگاری فراهم شده توسط ماژول crypto، مانند crypto.pbkdf2()، crypto.randomBytes() یا crypto.randomFill().    - عملیاتهای فشردهسازی داد فراهم شده توسط ماژول zlib.دقت کنید که کتابخانههای بومی جداگانه مانند bcrypt هم محاسبات را به داخل worker thread pool خالی میکنند.حال که باید یک درک بهتر از معماری کلی Node.js داشته باشید، بیایید دستور العملهای مربوط به نوشتن یک برنامه سمت سرور با کارایی بالاتر، و امنتر را مورد بحث قرار دهیم.قانون اول - از ترکیب Sync و Async در توابع خودداری کنیدوقتی که یک تابع مینویسید، یا باید آنها را کامل همگام کنیم، یا کاملا ناهمگام. شما باید از ترکیب این رویکردها در یک تابع تکی خودداری کنید.نکته: یک تابع یک callback را به عنوان یک آرگومان میپذیرد، اما به این معنی نیست که ناهمگام است. به عنوان مثال میتوانید به تابع Array.forEeach() فکر کنید. یک رویکرد این چنینی اغلب با نام «استایل منتقل کردن ادامه دار» (CPS = Continuation-passing style) شناخته میشود.بیایید این کد را به عنوان یک مثال در نظر بگیریم:const fs = require(&#x27;fs&#x27;) function checkFile (filename, callback) {  if (!filename || !filename.trim()) {    // تلهها در اینجا هستند:    return callback(new Error(&#x27;Empty filename provided.&#x27;))  }   fs.open(filename, &#x27;r&#x27;, (err, fileContent) =&gt; {    if (err) return callback(err)     callback(null, true)  })}این تابع بسیار ساده است، اما همچنان برای نیازهای ما کافیست. در اینجا مشکل ما شاخه return callback(…) است؛ زیرا callback مورد نظر در هنگام رو در رویی با یک آرگومان نامعتبر، به صورت همگام فراخوانی میشود. در سمت دیگر و در هنگام رو در رویی با یک ورودی معتبر، callback مورد نظر به روش async، داخل دستور fs.open() فراخوانی میشود.برای نمایش مشکل احتمالی این کد، بیایید آن را با ورودیهای مختلفی آزمایش کنیم:checkFile(&#x27;&#x27;, () =&gt; {  console.log(&#x27;#1 Internal: invalid input&#x27;)})console.log(&#x27;#1 External: invalid input&#x27;) checkFile(&#x27;main.js&#x27;, () =&gt; {  console.log(&#x27;#2 Internal: existing file&#x27;)})console.log(&#x27;#2 External: existing file&#x27;)کد ما این نتیجه را در کنسول خروجی خواهد داد:#1 Internal: invalid input#1 External: invalid input#2 External: existing file#2 Internal: existing fileممکن است که حال هم در اینجا متوجه مشکل شده باشید. ترتیب اجرای کد در این موارد متفاوت است. این ترتیب، تابع ما را غیر قطعی میکند، و از این رو باید از یک استایل این چنینی خودداری شود. تابع میتواند با جمعبندی return callback() با setImmediate&#40;&#41; یا process.nextTick() به یک استایل کاملا async تبدیل شود.if (!filename || !filename.trim()) {  return setImmediate&#40;    (&#41; =&gt; callback(new Error(&#x27;Empty filename provided.&#x27;))  )}حال تابع ما بسیار قطعیتر خواهد بود.قانون دوم - حلقه رویداد را مسدود نکنیدبه لحاظ وباپلیکیشنهای سمت سرور، برای مثال سرویسهای RESTful، تمام درخواستها به صورت همزمان داخل thread تکی حلقه رویداد پردازش میشوند. پس برای مثال اگر پردازش یک درخواست HTTP در برنامه شما زمان قابل توجهی را بر روی اجرای یک تابع JavaScript که یک محاسبه سنگین را انجام میدهد صرف میکند، این پردازش حلقه رویداد را برای تمام درخواستهای دیگر مسدود میکند. به عنوان یک مثال دیگر، اگر برنامه شما ۱۰ میلی ثانیه را بر روی پردازش کد JavaScript مربوط به هر درخواست HTTP صرف میکند، بازده یک نمونه تکی از برنامه شما حدود 1000 / 10 = 100 درخواست بر ثانیه خواهد بود.از این رو، اولین قانون طلایی Node.js این است که «هیچ وقت حلقه رویداد را مسدود نکنیم». در اینجا یک لیست کوتاه از پیشنهادات را مشاهده مینمایید که به شما در پیروی از این قانون کمک خواهند کرد:    از هر محاسبه JavaScript سنگینی خودداری کنید. اگر هر کدی دارید که پیچیدگی زمانی بیش از حدی دارد، بهینهسازی آن یا حداقل تقسیم محاسبات به قطعههایی که به صورت برگشتی و از طریق یک API تایمر مانند setTimeout&#40;&#41; یا setImmediate&#40;&#41; فراخوانی میشوند را در نظر داشته باشید. به این صورت شما در حال مسدود کردن حلقه رویداد نخواهید بود و هر callback دیگری خواهد توانست که پردازش شود.    از تمام فراخوانیهای *Sync مانند fs.readFileSync() یا crypto.pbkdf2Sync() در برنامههای سرور خودداری کنید. تنها استثنا برای این قانون، میتواند فاز اولیه برنامه شما باشد.    کتابخانههای جداگانه را به صورت عاقلانه انتخاب کنید؛ زیرا آنها ممکن است حلقه رویداد را مسدود کنند. مثلا با اجرای محاسبات حساس به CPU در JavaScript.قانون سوم - Worker Pool را به صورت عاقلانه مسدود کنیدشاید تجعبآور باشد، اما Worker Pool هم ممکن است مسدود شده باشد. همانطور که میدانید، Worker Pool یک ابزار thread با اندازه مشخص و با مقدار پیشفرض چهار thread میباشد. اندازه مورد نظر میتواند با تنظیم متغیر محیط UV_THREADPOOL_SIZE افزایش یابد، اما در بسیاری از موارد مشکل شما را حل نخواهد کرد.برای نمایش مشکل Worker Pool، بیایید این مثال را در نظر بگیریم: اِیپیآی RESTful شما یک اندپوینت احراز هویت دارد که مقدار hash را برای پسوورد داده شده محاسبه کرده، و آن را با مقدار دریافت شده از یک دیتابیس تطبیق میدهد. اگر شما همه چیز را به درستی انجام داده باشید، hash کردن در Worker Pool انجام میشود. بیایید فرض کنیم که محاسبه برای به اتمام رسیدن، حدود ۱۰۰ میلی ثانیه زمان میبرد. این یعنی با اندازه Worker Pool پیشفرض، شما تقریبا 4 * (1000 / 100) = 40 درخواست بر ثانیه را به لحاظ بازده اندپوینت hash کردن دریافت خواهید کرد. (نکته: ما موقعیتی با یک CPU دارای ۴ هسته به بالا را در نظر میگیریم) درحالیکه تمام threadها در Worker Pool مشغول هستند، تمام وظایف ورودی مانند محاسبات hash یا فراخوانیهای fs صفبندی (queue) خواهند شد.پس دومین قانون طلایی Node.js این است که «Worker Pool را به صورت عاقلانه مسدود کنیم.» در اینجا یک لیست کوتاه از پیشنهادات را مشاهده مینمایید که به شما در پیروی از این قانون کمک خواهند کرد:    از بروز دادن وظایف طولانی مدت در Worker Pool خودداری کنید. به عنوان مثال، APIهای بر پایه stream را نسبت به خواندن کل فایل با fs.readFile&#40;&#41; ترجیح دهید.    در صورت امکان، بخشبندی وظایف حساس به CPU را در نظر داشته باشید.    باز هم تاکید میکنم که کتابخانههای جداگانه را به صورت عاقلانه انتخاب کنید.قانون صفر - یک قانون برای حکمرانی همهحال به عنوان خلاصه، ما میتوانیم یک قانون کلیدی برای نوشتن یک برنامه سمت سرور Node.js با کارایی بالاتر را شکل دهیم. این قانون کلیدی عبارت است از این که: «اگر کار انجام شده برای هر درخواست در زمان داده شده کوتاه باشد، Node.js سریع است.» این قانون هم حلقه رویداد و هم Worker Pool را پوشش میدهد.</description>
                <category>مهران فریدونی</category>
                <author>مهران فریدونی</author>
                <pubDate>Tue, 06 Aug 2024 10:40:22 +0330</pubDate>
            </item>
            </channel>
</rss>