<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های رهام رفیعی تهرانی</title>
        <link>https://virgool.io/feed/@roham.tehrani</link>
        <description>برنامه نویسی یک شغل نیست، یک هنره.</description>
        <language>fa</language>
        <pubDate>2026-04-15 09:59:12</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/52004/avatar/TBZ1jE.jpg?height=120&amp;width=120</url>
            <title>رهام رفیعی تهرانی</title>
            <link>https://virgool.io/@roham.tehrani</link>
        </image>

                    <item>
                <title>چرا توسعه‌دهندگان Angular هنوز از ::ng-deep استفاده می‌کنند؟</title>
                <link>https://virgool.io/@roham.tehrani/%DA%86%D8%B1%D8%A7-%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%AF%D9%87%D9%86%D8%AF%DA%AF%D8%A7%D9%86-angular-%D9%87%D9%86%D9%88%D8%B2-%D8%A7%D8%B2-ng-deep-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D9%85%DB%8C-%DA%A9%D9%86%D9%86%D8%AF-nwmhz1yq1eol</link>
                <description>با وجود اینکه ::ng-deep از نسخه‌های ابتدایی Angular به‌عنوان یک راه‌کار برای نفوذ به سبک‌دهی داخل کامپوننت‌ها معرفی شد و بعدها به‌طور رسمی منسوخ (deprecated) اعلام شد، هنوز هم در بسیاری از پروژه‌های Angular دیده می‌شود. در این مقاله به دلایل ادامه‌دار بودن استفاده از ::ng-deep در سال ۲۰۲۵ می‌پردازیم و راهکارهای جایگزین را بررسی می‌کنیم.۱. چیستی ::ng-deepAngular به‌صورت پیش‌فرض استایل‌های هر کامپوننت را با مکانیزم «انکپسولاسیون» (Encapsulation) ایزوله می‌کند تا سبک‌ها به بیرون از همان کامپوننت نشت نکنند. اما در مواردی که لازم باشد استایلی را از والد به فرزند یا از یک لایه کامپوننت به لایه‌های عمیق‌تر اعمال کنیم (مثلاً هنگام تغییر ظاهر کامپوننت‌های شخص‌ثالث)، دستور ::ng-deep به‌عنوان یک «شکاف» (deep selector) معرفی شد تا بتوان این انکپسولاسیون را موقتاً دور زد./* نمونه استفاده */:host ::ng-deep .mat-button {    background-color: #1976d2;}۲. چرا با وجود منسوخ‌بودن هنوز استفاده می‌شود؟۲.۱. نبود جایگزین کامل و یکپارچهتا امروز Angular راه‌حل رسمی و یکسانی برای تمام حالات پیچیده استایل‌دهی ارائه نکرده است. ابزارهایی مثل :host، :host-context و حتی استایل‌های جهانی (global styles) در برخی موقعیت‌ها کارآمد هستند، اما در بسیاری از حالات، به‌ویژه وقتی با کامپوننت‌های شخص‌ثالث (مثل Angular Material یا PrimeNG) سروکار دارید، این ابزارها ناکافی‌اند.۲.۲. حجم زیاد کدهای قدیمیبسیاری از اپلیکیشن‌های بزرگ و سازمانی از سال‌ها قبل با ::ng-deep نوشته شده‌اند. بازنویسی و حذف تدریجی این دستور در هزاران فایل می‌تواند بسیار زمان‌بر و پرریسک باشد و تیم‌ها ترجیح می‌دهند با همان راه‌کار شناخته‌شده به‌کار ادامه دهند.۲.۳. ریسک بالا در تغییر انکپسولاسیونبرخی تیم‌ها برای دور زدن محدودیت‌های استایل‌دهی، کل انکپسولاسیون را با ViewEncapsulation.None غیرفعال می‌کنند که باعث می‌شود تمام استایل‌ها به‌صورت سراسری اعمال شوند. این رویکرد ریسک تداخل استایل‌ها را افزایش می‌دهد و نگهداری آن دشوار است. بنابراین ::ng-deep همچنان گزینه‌ی کم‌دردسرتر به نظر می‌رسد.۲.۴. پشتیبانی پنهان در Angularهرچند ::ng-deep منسوخ شده، تیم Angular هنوز آن را در هسته‌ی فریم‌ورک نگه داشته و حذف رسمی آن را به آینده نامعلومی موکول کرده است. همین امر توسعه‌دهندگان را مطمئن می‌سازد که فعلاً از کاربرد این دستور در پروژه‌هایشان پشتیبانی ادامه می‌یابد.---۳. معایب استفاده مداوم از ::ng-deep1. فنی بدهی (Technical Debt): انباشت دستور‌های منسوخ در کد باعث پیچیدگی و دشواری نگهداری می‌شود.2. کاهش خوانایی: ورود مکرر ::ng-deep به فایل‌های CSS/SCSS باعث می‌شود کد استایل از اصول مدرن Angular دور شود.3. ریسک در آینده: وقتی فرمان حذف کامل این قابلیت توسط تیم Angular صادر شود، بازنویسی یکباره بخش بزرگی از کد به‌همراه ریسک خطاها خواهد بود.---۴. راهکارهای جایگزین1. استفاده از CSS Variables: تعریف متغیرهای سراسری در :root و استفاده از آن‌ها در کامپوننت‌های مختلف.2. استایل‌دهی از طریق API کامپوننت‌ها: اگر کتابخانه‌ای از شما API یا کلاس‌های کمکی برای سفارشی‌سازی ارائه می‌دهد، به جای دستکاری CSS، از آن استفاده کنید.3. Tailwind CSS یا CSS Modules: با ورود فریم‌ورک‌های جدید، می‌توانید از رویکرد utility-first یا ماژولار برای جداسازی دقیق استایل بهره ببرید.4. تغییر انکپسولاسیون به Shadow DOM: در صورت امکان، از ViewEncapsulation.ShadowDom برای جداسازی واقعی استایل استفاده کنید و با ::part و ::theme استایل‌های لازم را تزریق نمایید.---۵. نتیجه‌گیریدر سال ۲۰۲۵، ::ng-deep هنوز زنده است نه به دلیل مطلوبیت فنی، بلکه به دلیل عملیاتی بودن آن در شرایط خاص و نبود جایگزین یکپارچه. با این حال، توصیه می‌شود برای آینده‌نگری و کاهش بدهی فنی، استفاده از این دستور را به حداقل برسانید، راهکارهای مدرن‌تر را جایگزین کنید و در صورت ادامه‌ی استفاده، به‌خوبی مستندسازی و محدودسازی کنید.---نظر شما چی هست؟ هنوز در پروژه‌های خود از ::ng-deep استفاده می‌کنید؟ راهکار جایگزین شما چه بوده؟ لطفاً تجربیات‌تان را به اشتراک بگذارید!امیدوارم از این مقاله لذت ببرید و براتون مفید باشه.اگر دوست دارید میتونید از طریق صفحه لینکدین با من در ارتباط باشید :)موفق باشید :)</description>
                <category>رهام رفیعی تهرانی</category>
                <author>رهام رفیعی تهرانی</author>
                <pubDate>Thu, 26 Jun 2025 15:27:35 +0330</pubDate>
            </item>
                    <item>
                <title>استفاده از command pattern در انگولار</title>
                <link>https://virgool.io/codenevis/%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-command-pattern-%D8%AF%D8%B1-%D8%A7%D9%86%DA%AF%D9%88%D9%84%D8%A7%D8%B1-ono87lr623qx</link>
                <description>در برنامه‌نویسی رابط کاربری با Angular، اغلب با سناریوهایی مواجه می‌شیم که شامل چندین اقدام پیچیده، مدیریت وضعیت‌ها و تعاملات متعدد با سرویس‌ها هستند. تو این وضعیت، پیاده‌سازی مستقیم منطق در کامپوننت‌ها می‌تونه کد رو نامرتب و سخت کنه برای تست و نگهداری. الگوی Command یک راه‌حل ساختاریافته برای این مشکل ارائه می‌دهد.جدا کردن منطق از UI همیشه خوبه. ولی استفاده از command pattern به مراتب تمیزتر و مرتب تر هست.چون برای جدا کردن منطق از UI به روش های دیگه باید کلی داکیومنت بنویسیم و توضیح بدیم . به نظرم من مزیت روش Command Pattern حذف کلی توضیح و داکیومنت هست. خوبی استفاده پترن ها بجای روش های خودساخته اینه که خیلی کمتر نیاز به داکیومنت و صحبت هست. یک اصطلاح دو کلمه ای به اندازه دو صفحه توضیح کار میکنه.در این مقاله، با نحوه استفاده از الگوی Command در Angular برای سامان‌دهی بهتر به منطق اقدامات پیچیده آشنا میشیم.معرفی الگوی Commandتعریف رسمی: الگوی Command یکی از الگوهای طراحی رفتاری است که یک درخواست را به‌صورت یک شیء کپسوله می‌کند. این الگو به ما اجازه می‌دهد درخواست‌ها را پارامترسازی، صف‌بندی، بازگردانی (undo/redo) و ثبت کنیم.ساختار کلی:هر کلاس Command معمولاً وابسته به یک گیرنده (Receiver) است که کار واقعی را انجام می‌دهد.اول مزایای استفاده از این الگو رو ببینیم و بعد بریم برای پیاده سازیچرا از Command Pattern در Angular استفاده کنیم؟جداسازی منطق از UIاقداماتی مانند ذخیره‌سازی، حذف، ویرایش و ارسال میتونن از کامپوننت‌ها جدا شده و در کلاس‌های مجزا قرار بگیرند.افزایش تست‌پذیریکلاس‌های Command به راحتی قابل تست هستند بدون نیاز به UI.قابلیت undo/redoاجرای مجدد یا لغو اقدامات خیلی ساده‌تر میشه.هماهنگی آسان‌تری بین چند سرویس یا منابع داده ایجاد میشه و مخصوصاً در اپلیکیشن‌های بزرگ با تعامل‌های پیچیده خیلی مفید تره.پیاده‌سازی نمونه در Angularبیاین روی سناریوی «ذخیره یک کاربر» کار کنیمفرض کنید بخواهیم یک کاربر را ذخیره کنیم. این عملیات شامل بررسی وجود کاربر، تماس با API و به‌روزرسانی UI است.۱. تعریف رابط Command:۲. تعریف کلاس ذخیره کاربر:3. استفاده در کامپوننت:پشتیبانی از Undo/Redoاگر بخواهیم undo رر اضافه کنیم، می‌تونیم رابط Command رو گسترش بدیم:و مثلاً در DeleteUserCommand:سازمان‌دهی بهتر با Command Dispatcherبرای مدیریت مرکزی دستورات، می‌توان یک سرویس CommandDispatcher ساخت:و در کامپوننت استفاده کرد:نتیجه‌گیریاستفاده از الگوی Command در Angular یک روش مؤثر برای مدیریت اقدامات پیچیده رابط کاربری به حساب میاد. این الگو با جدا کردن منطق اقدام‌ها از کامپوننت‌ها، باعث میشه کد تمیزتر، منعطف‌تر و تست‌پذیرتر بشه. در پروژه‌های متوسط تا بزرگ، استفاده از این الگو می‌تونه تأثیر زیادی در ساختار و کیفیت کد داشته باشه.امیدوارم از این مقاله لذت ببرید و براتون مفید باشه.اگر دوست دارید میتونید از طریق صفحه لینکدین با من در ارتباط باشید :)موفق باشید :)</description>
                <category>رهام رفیعی تهرانی</category>
                <author>رهام رفیعی تهرانی</author>
                <pubDate>Wed, 11 Jun 2025 18:18:27 +0330</pubDate>
            </item>
                    <item>
                <title>مروری بر ویژگی‌های برجسته انگولار ۲۰</title>
                <link>https://virgool.io/@roham.tehrani/%D9%85%D8%B1%D9%88%D8%B1%DB%8C-%D8%A8%D8%B1-%D9%88%DB%8C%DA%98%DA%AF%DB%8C-%D9%87%D8%A7%DB%8C-%D8%A8%D8%B1%D8%AC%D8%B3%D8%AA%D9%87-%D8%A7%D9%86%DA%AF%D9%88%D9%84%D8%A7%D8%B1-%DB%B2%DB%B0-ddiwn744bydw</link>
                <description>چند روز پیش یک مقاله خواندم در مورد ویژگی های مهم انگولار ۲۰ که قراره در اواخر ماه می ۲۰۲۵ منتشر بشه. در این مقاله میخوایم این ویژگی‌های جدید و جذاب رو مرور کنیم. ظاهرا نسخه ۲۰ انگولار قراره با تغییرات اساسی و بهبودهای قابل توجهی همراه بشه که توسعه‌دهندگان رو حسابی هیجان‌زده کرده.۱. خداحافظ Zone.js، سلام به Zoneless Change Detectionانگولار از نسخه ۱۸ به سمت حذف وابستگی به Zone.js حرکت کرده و سیستم جدیدی به نام &quot;Zoneless Change Detection&quot; معرفی کرده. در نسخه ۲۰ قرار واقعا Zone.js رو حذف کنید. این تغییر باعث می‌شه:عملکرد اولیه و زمان اجرا سریع‌تر بشهحجم بسته‌ها کاهش پیدا کنهاشکال‌زدایی ساده‌تر و کارآمدتر بشهبرای استفاده از این قابلیت، کافیه Zone.js رو از پروژه‌تون حذف کنید و از ابزارهایی مثل ChangeDetectorRef یا ApplicationRef برای مدیریت تغییرات استفاده کنید.۲. فرم‌های مبتنی بر Signalsیکی از ویژگی‌های مورد انتظار در انگولار ۲۰، معرفی فرم‌های مبتنی بر Signals هست. این فرم‌ها:با سیستم واکنش‌پذیری انگولار هماهنگ‌تر هستندبرای فرم‌های پیچیده مقیاس‌پذیری بهتری دارندبه‌صورت خودکار با استفاده از computed signals به‌روزرسانی می‌شناین تغییرات باعث می‌شن مدیریت فرم‌ها ساده‌تر و کارآمدتر بشه.۳. کامپوننت‌های بدون Selectorانگولار در حال بررسی امکان استفاده از کامپوننت‌هایی بدون نیاز به تعریف selector هست. این ویژگی:کدهای اضافی رو کاهش می‌دهمدیریت وابستگی‌ها رو ساده‌تر می‌کنهتوسعه کامپوننت‌ها رو سریع‌تر می‌کنهاین تغییر می‌تونه تجربه توسعه‌دهندگان رو بهبود بده و کدها رو تمیزتر کنه.۴. جایگزینی Karma با ابزارهای مدرن‌تربا کنار گذاشتن Karma، انگولار به دنبال جایگزین‌هایی مثل Web Test Runner، Jest و Vitest هست. این ابزارها:سرعت اجرای تست‌ها رو افزایش می‌دنتجربه بهتری برای توسعه‌دهندگان فراهم می‌کننبا محیط‌های مدرن‌تر سازگارتر هستنداین تغییرات باعث می‌شن فرآیند تست‌نویسی ساده‌تر و مؤثرتر بشه.۵. پشتیبانی از Nitro در Angular CLIانگولار در حال بررسی ادغام Nitro، یک سیستم ساخت مبتنی بر Rust، با Angular CLI هست. این ادغام:سرعت ساخت و توسعه پروژه‌ها رو افزایش می‌دهبهینه‌سازی‌های بهتری ارائه می‌دهتجربه توسعه‌دهندگان رو بهبود می‌بخشهاین تغییر می‌تونه زمان توسعه رو کاهش بده و بهره‌وری رو افزایش بده.جمع‌بندیانگولار ۲۰ با تمرکز بر بهبود عملکرد، ساده‌سازی توسعه و ارتقاء تجربه کاربری، یه قدم بزرگ به سمت آینده‌ای مدرن‌تر و کارآمدتر برداشته.برای نصب نسخه بتا یا RC انگولار ۲۰، می‌تونید از دستور زیر استفاده کنید:npm install @angular/cli@nextng new angular-20-democd angular-20-demonpm install @angular/core@nextآخرش در فایل main.ts، برای فعال‌سازی حالت بدون Zone.js، خط مربوط به zone.js رو حذف کنید.با این تغییرات، می‌تونید از قابلیت‌های جدید انگولار ۲۰ بهره‌مند بشید و تجربه توسعه بهتری داشته باشید.امیدوارم از این مقاله لذت ببرید و براتون مفید باشه.اگر دوست دارید میتونید از طریق صفحه لینکدین با من در ارتباط باشید :)موفق باشید :)</description>
                <category>رهام رفیعی تهرانی</category>
                <author>رهام رفیعی تهرانی</author>
                <pubDate>Sat, 31 May 2025 09:49:09 +0330</pubDate>
            </item>
                    <item>
                <title>همه چی درباره‌ی Epic، Story و Task</title>
                <link>https://virgool.io/@roham.tehrani/%D9%87%D9%85%D9%87-%DA%86%DB%8C-%D8%AF%D8%B1%D8%A8%D8%A7%D8%B1%D9%87-%DB%8C-epic-story-%D9%88-task-%D8%AF%D8%B1-srcrum-spxb0szmbaxm</link>
                <description>اگه با جیرا یا ابزار های مشابه کار کرده باشی و پروژه‌هات رو با اسکرام یا کانبان پیش برده باشی، احتمال زیاد با سه‌ تا اسم برخورد کردی: Epic، Story و Task. حالا سوالی که همیشه پیش میاد اینه که اینا چی‌ان؟ چه فرقی با هم دارن؟ کِی باید از کدوم استفاده کنیم؟فرض کن یه نفر قراره یه سیستم بزرگ طراحی کنه. اون کسی که ایده داره و می‌دونه چی می‌خواد، بهش می‌گن Product Owner. اما اون که قراره کد بزنه و پیاده کنه، توسعه‌دهنده‌ست. این وسط باید یه جوری ارتباط برقرار شه.اینجاست که «User Story» وارد می‌شه. یه جور جمله‌ست که می‌گه: «به عنوان فلان نقش، می‌خوام فلان کار رو بکنم، تا به فلان نتیجه برسم.» همین! هیچ حرفی از کد یا دیتابیس یا تکنولوژی نیست.ولی بعضی وقتا این داستان‌ها خیلی بزرگ‌ می‌شن. اون‌ قدر که دیگه نمی‌شه گفت یه داستانه. باید بشکنیش به تیکه‌های کوچک‌تر. اون داستان بزرگ اسمش می‌شه Epic.مثال بزنم: می‌خوای یه سایت آموزشی مثل یودمی بسازی؟ خب یه Epic می‌تونه «مدیریت دوره‌ها» باشه. توی این Epic، چندین Story هست مثل ساخت دوره، ویرایشش، گذاشتن قیمت و غیره.حالا Story هم که گفتیم، داستان کاربره. ولی وقتی میری توی برنامه‌ریزی Sprint، تیم توسعه میاد می‌گه خب برای پیاده کردن این Story، باید فلان کار و فلان کار انجام شه. این کارای کوچیک‌تر می‌شن Task.در واقع Task همون چیزیه که یه برنامه‌نویس یا متخصص DevOps یا QA باید انجام بده تا اون Story واقعاً کامل شه.پس چی شد؟مفهوم Epic: یه داستان بزرگ که از چند تا Story کوچیک‌تر تشکیل شدهمفهوم Story: خواسته‌ی کاربر، بدون حرف فنیمفهوم Task: کارای ریز و واقعی که باید انجام بشه تا اون Story به نتیجه برسهامیدوارم از این مقاله لذت ببرید و براتون مفید باشه.اگر دوست دارید میتونید از طریق صفحه لینکدین با من در ارتباط باشید :)موفق باشید :)</description>
                <category>رهام رفیعی تهرانی</category>
                <author>رهام رفیعی تهرانی</author>
                <pubDate>Wed, 28 May 2025 10:25:20 +0330</pubDate>
            </item>
                    <item>
                <title>سوگیری های ذهنی</title>
                <link>https://virgool.io/@roham.tehrani/%D8%B3%D9%88%DA%AF%DB%8C%D8%B1%DB%8C-%D9%87%D8%A7%DB%8C-%D8%B0%D9%87%D9%86%DB%8C-wgtpau0gj6td</link>
                <description>یک مقاله ای رو چند وقت پیش در مورد سوگیری های ذهنی مطالعه کردم و خیلی خوشم اومد. اصلش در مورد مدیریت محصول بود ولی احساس کردم به کار ما برنامه نویس ها هم میاد. ترجمه ش کردم که تو محتوای فارسی هم باشه و شما هم استفاده کنین.آیا تا به حال پیش اومده که یقین داشته باشید فیچر جدیدی که طراحی کردید یا توسعه دادید دقیقاً همون چیزیه که کاربران بهش نیاز دارند، اما بعداً متوجه بشید اون قدرها هم مهم نبوده؟ همه ما موقع تصمیم‌گیری ممکنه دچار پیش‌داوری بشیم، حتی بهترین آدم ها هم ممکنه دچار پیش داوری بشن.ما آدم ها خیلی مواقع به غرایز و تجربیات‌مون تکیه می‌کنیم. اما یک نکته‌ای وجود داره: ذهن ما گاهی بازی‌مون میده و باعث بروز سوگیری‌هایی میشه که تصمیمات ما را به‌طور نامحسوس تحت تأثیر قرار میده. بیاید چند مورد رو مرور کنیم که بیشتر از بقیه اتفاق می افتند:سوگیری تأییدی (Confirmation Bias)انسان‌ها ذاتا تمایل دارند اطلاعاتی رو جست‌وجو کنند که باورهای فعلی‌شان رو تأیید کنه. مثلا این ممکنه به معنای تمرکز بر بازخوردهایی باشه که ایده‌های ما رو تأیید می‌کنن و نادیده گرفتن داده‌های متناقض. خطرش؟ ممکنه فیچرهایی بسازیم که فکر می‌کنیم درست هستند، نه چیزی که واقعاً کاربران نیاز دارند.سوگیری لنگر انداختن (Anchoring ‌Bios)وقتی بیش از حد به اولین اطلاعاتی که دریافت می‌کنیم تکیه می‌کنیم، این سوگیری شکل می‌گیره. مثلاً اگر اولین تست کاربری نشون بده یک فیچر خیلی مهمه، ممکنه اون رو بیش از حد در اولویت قرار بدیم، حتی اگر داده‌های بعدی خلافش رو نشون بده.سوگیری در دسترس بودن (Availability Heuristic)ما معمولاً اهمیت اطلاعاتی که به‌راحتی در دسترس یا تازه هستند رو بیش از حد تخمین می‌زنیم. اگر یک مشکل یا درخواست فیچر به تازگی مطرح شده باشه، ممکنه در برنامه‌ریزی بیش از حد بهش بها بدهیم.اثر موج همراهی (Bandwagon Effect)پیروی از جمع کار ساده‌ایه. اگر همه از یک روند یا فیچر خاص حمایت کنند، ممکنه ما هم بدون بررسی تطابق اون فیچر با اهداف محصول یا نیاز کاربران، دنباله‌رو بقیه بشیم.راهکارهایی برای مقابله با سوگیری‌ها۱. تنوع دیدگاه‌ها: از افراد با پیش‌زمینه‌های مختلف در تیم مون استفاده کنیم. دیدگاه‌های متفاوت اونها می‌تونه تصمیم‌گیری ما رو به چالش بکشه و غنی تر کنه.۲. تصمیم‌گیری مبتنی بر داده: به داده‌ها تکیه کنیم. از تحلیل رفتار کاربران و تحقیقات بازار برای انتخاب‌های آگاهانه بهره بگیریم، نه فقط حس شهودی.۳. بازخورد مستمر: به‌طور مداوم از کاربران و اعضای تیم بازخورد بگیریم. این کار کمک می‌کنه نقاط تاریک در درک مون رو شناسایی و رفع کنیم.۴. به چالش کشیدن فرضیات: همیشه از خودمون بپرسیم: «اگر اشتباه کرده باشیم چی؟» این طرز فکر فرهنگ تفکر انتقادی و شفافیت رو تقویت می‌کنه.۵. به‌روز ماندن: مدام درباره روندها و بینش‌های رفتاری جدید یاد بگیریم. آگاهی به‌روز به شناسایی و کنترل سوگیری‌ها کمک می‌کنه.نتیجهآگاهی از سوگیری‌های ذهنی و مدیریت آن‌ها بسیار حیاتیه. این فقط درباره تصمیم‌گیری بهتر نیست، بلکه درباره ساخت و توسعه محصولاتیه که واقعاً با طیف متنوع کاربران ارتباط برقرار می‌کنند.اولین قدم برای غلبه بر سوگیری‌ها، پذیرش اون هاست. بهتره همیشه در حال یادگیری، تطبیق و رشد باشیم.امیدوارم از این مقاله لذت ببرید و براتون مفید باشه.اگر دوست دارید میتونید از طریق صفحه لینکدین با من در ارتباط باشید :)اصل مقاله رو میتونید از اینجا مطالعه کنینموفق باشید :)</description>
                <category>رهام رفیعی تهرانی</category>
                <author>رهام رفیعی تهرانی</author>
                <pubDate>Tue, 20 May 2025 20:36:02 +0330</pubDate>
            </item>
                    <item>
                <title>آشنایی کامل با Core Web Vitals</title>
                <link>https://virgool.io/@roham.tehrani/%D8%A2%D8%B4%D9%86%D8%A7%DB%8C%DB%8C-%DA%A9%D8%A7%D9%85%D9%84-%D8%A8%D8%A7-core-web-vitals-fard3lao2jxl</link>
                <description>مقدمهدر دنیای رقابتی امروز، سرعت و کیفیت بارگذاری وب‌سایت‌ها نقش اساسی در جذب و حفظ کاربران دارند. گوگل با معرفی مجموعه‌ای از شاخص‌های کلیدی تحت عنوان Core Web Vitals، به مدیران وب‌سایت‌ها ابزاری داده تا عملکرد وب‌سایت خود را از نظر تجربه کاربری بسنجند و بهبود دهند. در این مقاله به معرفی Core Web Vitals، اهمیت آن‌ها در سئو و نحوه بهینه‌سازی هر یک از این شاخص‌ها می‌پردازیم.بحث Core Web Vitals چیست؟در واقع Core Web Vitals مجموعه‌ای از شاخص‌های عملکردی است که توسط گوگل معرفی شده‌اند و بر تجربه کاربر در تعامل با صفحات وب تمرکز دارند. این شاخص‌ها از سال 2021 به عنوان یکی از فاکتورهای رتبه‌بندی گوگل در نظر گرفته شده‌اند.سه معیار اصلی Core Web Vitals عبارت‌اند از:• Largest Contentful Paint (LCP)• First Input Delay (FID)• Cumulative Layout Shift (CLS)(در نسخه‌های جدید، گوگل معیار FID را با INP جایگزین کرده است که در ادامه توضیح داده می‌شود.)معیار Largest Contentful Paint (LCP) - بزرگ‌ترین زمان بارگذاری محتوامعیار LCP نشان می‌دهد که بارگذاری بزرگ‌ترین عنصر محتوایی قابل مشاهده (مانند تصویر یا بلوک متنی) چقدر طول می‌کشد. این شاخص مستقیماً با سرعت درک اولیه صفحه توسط کاربر مرتبط است.• مقدار مناسب: کمتر از 2.5 ثانیهروش‌های بهینه‌سازی:• استفاده از هاستینگ سریع‌تر• بهینه‌سازی تصاویر و فایل‌های CSS• استفاده از بارگذاری تنبل (Lazy Loading)معیار First Input Delay (FID) - تأخیر اولین تعامل کاربر (در حال جایگزینی با INP)معیار FID زمان تأخیر بین اولین تعامل کاربر با صفحه (مثلاً کلیک روی دکمه) و پاسخ مرورگر به آن را اندازه‌گیری می‌کند. این معیار برای سنجش تعامل‌پذیری صفحه به‌کار می‌رود.• مقدار مناسب: کمتر از 100 میلی‌ثانیهروش‌های بهینه‌سازی:• کاهش حجم جاوااسکریپت• تقسیم‌بندی کدها (Code Splitting)• استفاده از Web Workersنکته: گوگل از سال 2024 شروع به جایگزینی FID با Interaction to Next Paint (INP) کرده است که تعامل‌های واقعی‌تری را در طول استفاده کاربر اندازه می‌گیرد.معیار Cumulative Layout Shift (CLS) - جابه‌جایی چیدمان تجمعیمعیار CLS میزان پایداری عناصر در صفحه را اندازه‌گیری می‌کند. اگر در هنگام بارگذاری، عناصر صفحه بدون اطلاع جابجا شوند، امتیاز CLS بالا می‌رود که نشان‌دهنده تجربه کاربری بد است.• مقدار مناسب: کمتر از 0.1روش‌های بهینه‌سازی:• مشخص کردن ابعاد تصاویر و ویدیوها• اجتناب از بارگذاری عناصر پویا بدون اطلاع کاربر• استفاده از فونت‌های بهینه‌سازی شدهاهمیت Core Web Vitals در سئواز ژوئن 2021، Core Web Vitals به‌عنوان بخشی از الگوریتم رتبه‌بندی گوگل شناخته می‌شود. این بدان معناست که:• وب‌سایت‌هایی که نمره خوبی در این معیارها دارند، شانس بیشتری برای قرار گرفتن در رتبه‌های بالاتر دارند.• تجربه کاربری بهتر باعث افزایش نرخ تبدیل، کاهش نرخ پرش و افزایش تعامل کاربران می‌شود.ابزارهای اندازه‌گیری Core Web Vitalsبرای بررسی این شاخص‌ها می‌توانید از ابزارهای زیر استفاده کنید:• Google PageSpeed Insights• Lighthouse• Chrome DevTools• Web Vitals Chrome Extension• Google Search Console (گزارش Core Web Vitals)جمع‌بندیتعاریف Core Web Vitals یک بخش ضروری از بهینه‌سازی تجربه کاربری و سئو مدرن هستند. با درک درست این معیارها و اجرای بهینه‌سازی‌های لازم، می‌توانید رتبه سایت خود را در نتایج جستجو ارتقا دهید و رضایت کاربران را افزایش دهید. این سه معیار – LCP، FID/INP و CLS – ابزاری هستند که باید در کنار سایر فاکتورهای سئو در اولویت قرار گیرند.امیدوارم از این مقاله لذت ببرید و براتون مفید باشه.اگر دوست دارید میتونید از طریق صفحه لینکدین با من در ارتباط باشید :)موفق باشید :)</description>
                <category>رهام رفیعی تهرانی</category>
                <author>رهام رفیعی تهرانی</author>
                <pubDate>Tue, 13 May 2025 20:19:48 +0330</pubDate>
            </item>
                    <item>
                <title>اصطلاح banana in the box در انگولار</title>
                <link>https://virgool.io/@roham.tehrani/%D8%A7%D8%B5%D8%B7%D9%84%D8%A7%D8%AD-banana-in-the-box-%D8%AF%D8%B1-%D8%A7%D9%86%DA%AF%D9%88%D9%84%D8%A7%D8%B1-ln5mc9bj5erb</link>
                <description>امروز با یک اصطلاح جالبی آشنا شدم که بارها و بارها دیده بودم و خودم درگیرش بودم ولی نمیدونستم براش اصطلاح خلاصه ای وجود داره.اسم اصطلاح هست banana in the box و مربوط به syntax در two-way binding انگولار هست و در داکیومنت جدید انگولار هم به عنوان اصطلاح غیررسمی در جامعه انگولار بهش اشاره شده.روش two-way binding در انگولار به صورت رسمی این شکلی هست:[(ngModel)]=”model”مثلا در یک کامپوننت سفارشی بنام my-input میتونیم از این روش استفاده کنیم:&lt;app-custom-input [(value)]=”value”&gt;&lt;/app-custom-input&gt;در واقع این روش خلاصه نوشتن و خوانده مقدار model به صورت مجزا از هم هست:&lt;app-custom-input [text]=&quot;val&quot; (textChange)=&quot;val=$event&quot;&gt;&lt;/app-custom-input&gt;نمونه کامپوننت سفارشی مون میتونه به صورت زیر باشه:به این syntax خلاصه شده [()] میگن banana in the box .در واقع به [] میگن باکس و به () میگن موزامیدوارم از این مقاله لذت ببرید و براتون مفید باشه.اگر دوست دارید میتونید از طریق صفحه لینکدین با من در ارتباط باشید :)موفق باشید :)</description>
                <category>رهام رفیعی تهرانی</category>
                <author>رهام رفیعی تهرانی</author>
                <pubDate>Sun, 20 Apr 2025 11:13:34 +0330</pubDate>
            </item>
                    <item>
                <title>آشنایی با رنگ های ANSI در جاوااسکریپت</title>
                <link>https://virgool.io/@roham.tehrani/%D8%A2%D8%B4%D9%86%D8%A7%DB%8C%DB%8C-%D8%A8%D8%A7-%D8%B1%D9%86%DA%AF-%D9%87%D8%A7%DB%8C-ansi-%D8%AF%D8%B1-%D8%AC%D8%A7%D9%88%D8%A7%D8%A7%D8%B3%DA%A9%D8%B1%DB%8C%D9%BE%D8%AA-aylnhakdgedm</link>
                <description>دیروز با موضوعی آشنا شدم به اسم ANSI Colors یا رنگ های ANSI که برام جالب بود. این مقاله رو نوشتم که شما هم آشنا بشین.در جاوااسکریپت وقتی میخوایم متنی رو داخل کنسول بنویسیم از دستور console.log استفاده می‌کنیم.console.log(&amp;quotI&#039;m just the default text :(&amp;quot);و نتیجه ای که می‌بینیم یک متن سیاه روی بک گراند سفیدهاما به لطف چیزی به اسم ANSI escape sequesnces ما میتونیم کنترل بیشتری روی خروجی داشته باشیم و مشخص کنیم چطوری دیده بشه.در واقع ANSI escape sequesnces یک مجموعه از کدهای استاندارد هستند که به برنامه نویس اجازه میدن که به خروجی کنسول یا برنامه های متن پایه ( text based ) استایل بده. استفاده از این ANSI requences خیلی راحت و بانمکه.این مجموعه کدهای استاندارد باید با یک الگوی مشخص ( مجموعه کاراکترهای مشخص ) شروع میشن. به این الگو میگن escape code. در این مقاله از الگویی استفاده میکنیم که در همه زبان های رایج برنامه نویسی مثل جاوااسکریپت (Javascript)، پایتون (Python) و جاوا (Java) پشتیبانی میشه.\u001bبریم اولین نمونه از این کدهای دستوری رو ببینیم:خروجی این چند خط رو با هم ببینیم:دقت کنین که همه متن ها شامل escape code و style code و متن اصلی هستند:\u001b[ + style code (XXm) + output textکد های رنگ ANSI یا همون ANSI Colorsدر ANSI هشت کد رنگ اصلی داریم :سیاه = 30قرمز = 31سبز = 32زرد = 33آبی = 34سرخابی = 35فیروزه ای = 36سفید = 37مثال زیر نمونه خوبی برای استفاده این کدهاست:const RED = &quot;\u001b[31m&quot;;const BLUE = &quot;\u001b[34m&quot;;console.log(RED + &quot;I&#x27;m red!&quot;);console.log(BLUE + &quot;Or am I blue?&quot;);کد رنگ های پس زمینه ( Background ):لیست کد رنگ های پس زمینه به شرح زیر هستند:پس زمینه سیاه = 40پس زمینه قرمز = 41پس زمینه سبز = 42پس زمینه زرد = 43پس زمینه آبی = 44پس زمینه سرخابی = 45پس زمینه فیروزه ای = 46پس زمینه سفید = 47کد رنگ های پس زمینه بین ; و m قرار میگیرند و میتونن با رنگ متن یا بدون رنگ متن تنظیم بشن.text color + ; + background color + m مثال های زیر نمونه های خوبی هستند:و نتیجه خروجی ها رو ببینید:کدهای رنگ RGB در ANSIکدهای رنگ اضافه با دو الگوی قابل استفاده هستند. الگوی اول کد رنگ و الگوی دوم RGB هست.الگوی اول با کد رنگ:برای رنگ متن از الگوی زیر استفاده میکنیم:&quot;\u001b[38;5;&lt;color code&gt;m + output text&quot;برای رنگ پس زمینه هم از الگوی زیر استفاده میکنیم:&quot;\u001b[48;5;&lt;color code&gt;m + output text&quot;عکس زیر لیست کد رنگ هاست:الگوی دوم الگوی RGB هست:برای رنگ متن از الگوی زیر استفاده میکنیم:&quot;\u001b[38;2;&lt;R code&gt;;&lt;G code&gt;;&lt;B code&gt;m + output text&quot;و برای رنگ پس زمین از الگوی زیر استفاده میکنیم:&quot;\u001b[48;2;&lt;R code&gt;;&lt;G code&gt;;&lt;B code&gt; + output text&quot;در بخش بعدی می‌بینیم که چطور از این الگوها استفاده میکنیم.استفاده از رنگ های مختلف در یک متنمیتونیم داخل یک متن از رنگ های مختلفی استفاده کنیم. به مثال زیر توجه کنین:نتیجه میشه خروجی زیر:ریست کردن رنگ تنظیم شدهبرای برگشتن رنگ متن به رنگ پیش فرض از کد زیر استفاده میکنیم:[0mنمونه استفاده ش رو در کد زیر نوشتم:و خروجی زیر رو میبینیم:نکته مهم: در جاوااسکریپت ، موقع اجرای هر console.log خود به خود همه چیز بر اساس رنگ پیش فرض اجرا میشه و نیازی به کد ریست نیست:const WHITE_CYAN = &quot;\u001b[37;46m&quot;;console.log(WHITE_CYAN + &quot;I am colorful&quot;);// Does not have the same color as above, even with no manual resetconsole.log(&quot;But I am not&quot;);ولی در پایتون کنسول خود به خود ریست نمیشه و باید حتما دستور ریست اجرا بشه:WHITE_CYAN = &quot;\u001b[37;46m&quot;print(WHITE_CYAN + &quot;I am colorful&quot;)# Has the same color as above, since it was not manually resetprint(&quot;And so am I&quot;)استایل های دیگرسه کد دیگر که به عنوان ANSI Decoration معروف هستند عبارتند از:Bold: \u001b[1mItalicized: \u001b[3mUnderline: \u001b[4mسخن آخرحتما این موارد رو آزمایش کنید و خروجی بگیرید تا بیشتر به یادتون بمونه. من شخصا پکیج logger پروژه ام رو با این موارد آپدیت کردم.امیدوارم از این مقاله لذت ببرید و براتون مفید باشه.اگر دوست دارید میتونید از طریق صفحه لینکدین با من در ارتباط باشید :)متن مقاله اصلی رو میتونید اینجا مطالعه کنید.موفق باشید :)</description>
                <category>رهام رفیعی تهرانی</category>
                <author>رهام رفیعی تهرانی</author>
                <pubDate>Mon, 24 Mar 2025 19:16:56 +0330</pubDate>
            </item>
                    <item>
                <title>راه حل تعریف Path Alias در Jest</title>
                <link>https://virgool.io/@roham.tehrani/%D8%B1%D8%A7%D9%87-%D8%AD%D9%84-%D8%AA%D8%B9%D8%B1%DB%8C%D9%81-path-alias-%D8%AF%D8%B1-jest-v7ban5p2ewu7</link>
                <description>چند وقت یک پروژه Next رو تحویل گرفتم که توسعه ش بدم. یک خط کد تست براش نوشته نشده بود. منم کتابخونه Jest رو نصب کردم که شروع کنم روی پروژه تست بنویسم.به یک مشکل بزرگ رسیدم. Jest تنظیمات path aliases پروژه رو متوجه نمیشد. با توجه به تغییرات نسخه به نسخه ای که کرده، پیدا کردن راه حل برای نسخه های جدید یک کم طول کشید. برای همین تصمیم گرفتم یک مقاله درباره ش بنویسم.تنظیمات Path Alias در پروژهاول از همه ببنیم این تنظیمات داخل پروژه کجا انجام میشه.این تنظیمات به کامپایلر typescript مربوط میشه و بنابر این داخل فایل tsconfig.js نوشته میشه. داخل آبجکت compilerOptions و قسمت paths میتونیم تعریفشون کنیم:یا مثلا میتونه این جوری بشه:تنظیمات Path Alias در Jestدر NextJS با اولین اجرای دستور npm run test  به این خطا خوردم که import با حضور path alias رو متوجه نمیشه و خطا میده که این مسیر رو تشخیص نمیدم.در نسخه های جدید Next باید داخل فایل jest.config.js که با نصب کتابخونه Jest ساخته میشه ، path alias ها رو  در بخشی به عنوان moduleNameMapper تعریف کنیم:شاید چندین راه حل مختلف رو پیدا کردم که همگی قدیمی هستند و متاسفانه به خاطر بازدید بالا، جلوتر و بیشتر نمایش داده میشن. ولی بالاخره راه حل رو پیدا کردم.شبیه همین مقاله رو زمانی که انگولار کار میکردم به اسم آشنایی با Module Resolution در انگولار نوشتم.امیدوارم از این مقاله لذت ببرید و براتون مفید باشه.اگر دوست دارید میتونید از طریق صفحه لینکدین با من در ارتباط باشید :)اصل مقاله شامل پیاده سازی با جاوا هم هست. میتوانید مقاله اصلی رو اینجا مطالعه کنید.موفق باشید</description>
                <category>رهام رفیعی تهرانی</category>
                <author>رهام رفیعی تهرانی</author>
                <pubDate>Tue, 18 Mar 2025 15:04:08 +0330</pubDate>
            </item>
                    <item>
                <title>شمارش تعداد کاربران آنلاین در اپلیکیشن وب</title>
                <link>https://virgool.io/@roham.tehrani/%D8%B4%D9%85%D8%A7%D8%B1%D8%B4-%D8%AA%D8%B9%D8%AF%D8%A7%D8%AF-%DA%A9%D8%A7%D8%B1%D8%A8%D8%B1%D8%A7%D9%86-%D8%A2%D9%86%D9%84%D8%A7%DB%8C%D9%86-%D8%AF%D8%B1-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%88%D8%A8-wlrdgaimsben</link>
                <description>توانایی ردیابی تعداد کاربران آنلاین در یک وب اپلیکیشن برای مسائلی مثل میزان استقبال کاربران، بهینه سازی سرورها از لحاظ بازدهی و حتی مسائل امنیتی بسیار مهم و حیاتی است.چه برای یک بلاگ کوچک چه برای یک پلتفرم عریض و طویل، دانستن تعداد کاربران آنلاین در هر لحظه، اطلاعات  ارزشمند و مهمی رو به همراه داره.در این مقاله میخوایم راه حل های مختلف شمارش کاربران آنلاین رو مرور کنیم.بخش اول : درک مفهوم کاربر آنلاینقبل از اینکه به راه حل های فنی بپردازیم، اول به درک مشترکی از مفهوم کاربر آنلاین برسیم.در وب اپلیکیشن ها، یک کاربر آنلاین به کسی گفته میشه که یک جلسه ( session ) فعال روی پلتفرم داره یا به تازگی تعاملی با سرور داشته. به کمک کوکی ها ، session ها و web socket ها میتونیم این تعاملات رو رصد کنیم.یک کاربر آنلاین در بیشتر اپلیکیشن های وب به کسی گفته میشه که اخیرا صفحه ای باز کرده، تعاملی با سرور داشته، یا فعالیتی انجام داده. برای تعریف اخیرا باید بازه زمانی در نظر بگیریم. مثلا از الان تا ۵ دقیقه قبل.در اپلیکیشن های در لحظه (real-time) ، به کمک web socket ها میتونیم کاربران آنلاین رو با به روز رسانی وضعیت شون شناسایی کنیم.هر روشی مزایا و معایب خودش رو داره که در ادامه بهش میپردازیم.راهکارهای عمومی دریابی کاربران آنلاین عبارتند از: ردیابی session-basedردیابی token-based ( مثل jwt )ردیابی WebSocketدیتابیس های in-memory مثل Redis برای به روز رسانی های real-timeبخش دوم :‌ ردیابی Session-Based راه حل معروف و مستقیم ردیابی کاربران آنلاین استفاده از طریق session است. در جاوا هنگام استفاده از Spring Boot شما میتوانید از HttpSession برای مدیریت جلسات و ردیابی کاربران استفاده کنید.بخش سوم: ردیابی Token-basedبا نگهداری توکن های active و زمان انتقضای آنها در مثلا Redis، شما میتوانید تعداد توکن های ولید را در هر لحظه داشته باشید.بخش چهارم: ردیابی WebSocketبه ازای هر کاربر شما میتوانید یک ارتباط WebSocket بین کلاینت و سرور برقرار کنید. به محض قطع ارتباط، session ارتباطی حذف میشود. با شمارش تعداد ارتباطات فعال میتوانید کاربران در لحظه را شمارش کنید.امیدوارم از این مقاله لذت ببرید و براتون مفید باشه.اگر دوست دارید میتونید از طریق صفحه لینکدین با من در ارتباط باشید :)اصل مقاله شامل پیاده سازی با جاوا هم هست. میتوانید مقاله اصلی رو اینجا مطالعه کنید.موفق باشید</description>
                <category>رهام رفیعی تهرانی</category>
                <author>رهام رفیعی تهرانی</author>
                <pubDate>Sun, 16 Mar 2025 15:36:15 +0330</pubDate>
            </item>
                    <item>
                <title>زوم دو انگشتی در nextJS یا pinch zoom</title>
                <link>https://virgool.io/@roham.tehrani/%D8%B2%D9%88%D9%85-%D8%AF%D9%88-%D8%A7%D9%86%DA%AF%D8%B4%D8%AA%DB%8C-%D8%AF%D8%B1-nextjs-%DB%8C%D8%A7-pinch-zoom-owwrt0ptdsao</link>
                <description>هر چند سالی که در یک حوزه کار کنی، باز هم ممکنه موردی پیش بیاد که تا حالا باهاش برخورد نداشتی. به نظرم هر چقدر هم که این چالش کوچک یا بزرگ باشه، در هر حرفه و تخصصی خیلی جذابه.چند وقت پیش یک فیچری مطرح شد در اپ در حال توسعه مون. چی بود؟ قابلیت زوم دو انگشتی روی یک عکس که بشه روی عکس zoom in یا zoom out کرد.من هم از بین همه کارها روی این موضوع زوم کردم و برش داشتم. چون تا قبلش صرفا با event های touch آشنا بودم و مدل های دیگه ای از این event رو پیاده سازی کردم بودم. ولی این فیچر رو پیاده نکرده بودم.گفتم این فیچر رو با شما هم مطرح کنم، اگر برخورد نکردین حداقل چشم تون یه بار دیده باشه.این فیچر رو با تغییر نحوه نگه داشتن متغیرها و فراخوان event ها، میتونید در جاوااسکریپت vanilla هم استفاده کنید یا حتی فریم ورک محبوب من انگولار.لیست event هایی که لازم داریم:اولیش touchStartدومیش touchMoveسومیش touchEndوقتی که ما آبجکت مورد نظر در صفحه رو لمس میکنیم، ایونت touchStart فعال میشه. مادامی که دستمون رو روی صفحه حرکت میدیم، به صورت رگباری event های touchMove فعال میشن. در انتها که دستمون رو برمیداریم ایونت touchEnd فراخوانی میشه.این ایونت ها به این صورت صدا زده میشن:اگر به داخل آبجکت ایونت touchStart و touchMove نگاه کنیم، دو تا متغیر می بینیم که خیلی به کار ما میاد:touchestargetTouchesمتغیر targetTouches یک لیسته که اندازه ش برابره با تعداد انگشت های کاربر که همزمان صفحه رو تاچ میکنند. یعنی برای اینکه ببینیم دو انگشتی تاچ صورت گرفته یا نه، از کد زیر استفاده میکنیم:متغیر touches هم یک لیست از آبجکت هاییه که مختصات نقطه تاچ رو به ما میدهما اگر بتونیم فاصله بین دو نقطه تاچ رو در touchStart رو اندازه گیری کنیم و در یک متغیر نگه داریم،بعد فاصله بین دو نقطه تاچ در touchMove رو اندازه گیری کنیم و در یک متغیر دیگه دائم آپدیت کنیم،بعد در touchEnd این دو فاصله رو مقایسه کنیم،میتونیم بفهمیم که دو انگشت از هم دورتر  شدند یا نزدیک‌تر. اگر دورتر شده بودند zoom out کنیم و اگر نزدیک تر شدند zoom in کنیم.پس اول دو تا متغیر در کامپوننت nextjs تعریف میکنم. اولی برای نگه داشتن فاصله بین دو نقطه تاچ در touchStart و دومی برای نگه داشتن فاصله بین دو نقطه تاچ در touchMove:اگر مثلثات یادتون مونده باشه، میدونید که در مثلث قائم الزاویه، اندازه ضلع بزرگتر رو چطور به دست میارن:حالا فرض کنید دو طرف ضلع z در واقع دو نقطه تاچ ما هستند. مقدار x در واقع اختلاف pageY های دو نقطه تاچ و مقدار Y در واقع اختلاف pageX های دو نقطه تاچ ما هستند. معادلش بر اساس مقادیری که از طریق  event به ما منتقل میشه، کد پایینه:یه نکته دیگه از ریاضیات هم هست. وقتی یک عدد رو به توان دو میرسونیم، چه منفی باشه چه مثبت جواب یکیه. یعنی مقدار x به توان ۲ با -x به توان ۲ فرقی نداره. در واقع نیازی نیست که حتما ورودی ما مقدار مثبت باشه. میتونه منفی همون عدد هم باشه.من نمیدونستم ( یا خواندم ولی یادم رفته ) که جاوااسکریپت در کتابخانه Math ، همچین تابعی داره بنام hypot. مقدار Y و X رو ورودی می‌گیره و مقدار Z برمیگردونه. پس فاصله بین دو نقطه تاچ رو در ایونت های touchStart و touchMove با کد زیر به دست میاریم:این تابع از ۲۰۱۵ در مرورگرها پشتیبانی میشه. میتونیم مستقیما از Math.sqrt هم استفاده کنیم که قدیمی تره:در انتها ( ایونت touchEnd ) هم این دو مقدار رو مقایسه میکنیم و متوجه میشیم zoom in کردیم یا zoom outالگوریتم zoom in و zoom out رو جدا پیاده سازی کنید که از طرق دیگه هم بتونید پیاده سازیش کنین. مثلا با کلیک رو دکمه های zoom in , zoom out هم کاربر بتونه کار کنه.امیدوارم از این مقاله لذت ببرید و براتون مفید باشه.اگر دوست دارید میتونید از طریق صفحه لینکدین با من در ارتباط باشید :)موفق باشید</description>
                <category>رهام رفیعی تهرانی</category>
                <author>رهام رفیعی تهرانی</author>
                <pubDate>Tue, 17 Sep 2024 14:28:40 +0330</pubDate>
            </item>
                    <item>
                <title>در اپ انگولار از Signal استفاده کنیم یا RxJS ؟</title>
                <link>https://virgool.io/@roham.tehrani/%D8%AF%D8%B1-%D8%A7%D9%BE-%D8%A7%D9%86%DA%AF%D9%88%D9%84%D8%A7%D8%B1-%D8%A7%D8%B2-signal-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%DA%A9%D9%86%DB%8C%D9%85-%DB%8C%D8%A7-rxjs-ipng1bvnkqsf</link>
                <description>چند ماهی هست که تمرکزم روی NextJs هست . هفته اخیر اما برای پشتیبانی اپ انگولار وقت گذاشتم و یه کم به حال و هوای انگولار برگشتم. طی همین هفته یک مقاله در حوزه انگولار خواندم و حس کردم محتوای مفیدی ارائه داده و با تجربه های من هم خیلی سازگاره. تصمیم گرفتم همینجوری دلی به فارسی ترجمه ش کنم و اینجا با شما به اشتراک بگذارم.این مقاله مقایسه کاملی از کتابخانه های Signal (کتابخانه جدید) و RxJS (کتابخانه قدرتمند قدیمی) ارائه داده و کمک میکنه که توسعه دهنده انگولار بتونه تا با قدرت و تسلط بیشتری تصمیم بگیره که بین کتابخانه های Signal و RxJS کدوم رو انتخاب کنه.در این مقاله چکیده نقاط ضعف و قدرت و موارد استفاده هر کتابخانه بررسی میشه.کتابخانه RxJSکتابخانه RxJS سالها سنگ بنای مدیریت جریان دیتا (data stream) در اپلیکیشن های انگولار بوده. این کتابخانه دیتاهای Asynchronous رو مدیریت میکنه.یه نگاهی به نقاط قوت RxJS بندازیم:مجموعه ابزارهای کامل و متنوعی رو برای مدیریت جریان داده های پیچیده ارائه میدهبرای دیتاهای Asynchronous عالیهبرای مدیریت event ها عالیهامکان کنسل کردن subscription دارهنقاط ضعف کتابخانه RxJS عبارتند از:نیاز به یادگیری زیاد و عمیق دارهاگر subscription ها درست مدیریت نشوند، ممکنه باعث memory leak بشهبرای سناریوهای ساده بیش از حد توانمندهبهترین ابزاره برای:ریکوئست های httpمدیریت event های پیچیدهترکیب کردن جریان های دیتاکتابخانه Angular Signalابزار سیگنال در واقع یک wrapper هست دور یک مقدار (value) که تغییرات اون مقدار رو به اطلاع مصرف کننده ها (consumers) میرسونه. این ابزار هر نوع مقداری رو پشتیبانی میکنه ، از مقادیر primitive تا آبجکت های پیچیده.نقاط قوت Angular Signal:سادگی در پیاده سازی و مدل سازیبازدهی عالی در دیتاهای Synchronousامکان ادغام با change detection سنتی انگولارکاهش پیچیدگی ها و مشکلات عجیبنقاط ضعف Angular Signal:مجموعه امکانات کم نسبت به کتابخانه RxJSاز پایه برای دیتاهای Synchronous طراحی شدهجدیدتره و اکوسیستمش در حال توسعه استبهترین ابزاره برای:مدیریت وضعیت دیتاهای در سطح کامپوننتکنترل دیتاهای جانبی یا نتایج محاسباتاپلیکیشن هایی که سرعت عمل بسیار بالایی نیاز دارندتولید کد ساده و خوانا بدون پیچیدگی خاصیبرای همین بهتره:از Angular Signal برای مدیریت دیتاهای سطح کامپوننت استفاده کنیماز RxJS برای مدیریت ریکوئست ها ، event ها و دیتاهای Asynchronousامکانات toSignal و toObservable برای ادغام این دو ابزار قدرتمندمیشه از این دو تا ابزار قدرتمند در کارهای مربوط به خودشون استفاده کرد و به وقتش اون ها رو با هم ترکیب کرد. در واقع میتونیم ترکیبی از سادگی زیاد، عملکرد قوی و پیچیدگی مدیریت Asynchronous رو پیاده کنیم.مثال زیر نمونه خوبیه:شناسه کاربر (userId) یک دیتای سطح کامپوننته که تغییرش باعث ارسال ریکوئست به سرور و دریافت اطلاعات اون کاربر میشه. بنابر این مقدارش با یک سیگنال wrap میشه.ابزار toSignal به ما امکان میده که مقدار خروجی یک Observable رو با یک سیگنال wrap کنیم. پس ما نتیجه ریکوئست دریافت اطلاعات کاربر رو در یک سیگنال بنام userSignal نگه میداریم.در واقع اطلاعات کاربر به صورت یک متغیر در سطح کامپوننت نگه داشته میشه.یک دیتای جانبی هم نیاز داریم که تعداد پست های کاربر رو شامل میشه (postCount). بهترین ابزار برای نگهداری دیتاهای جانبی سیگناله. به محض تغییر دیتای اصلی، دیتای جانبی رو آپدیت میکنه و در اختیار مصرف کننده ها قرار میدهبنابر این با صدا کردن تابع updateUser و در صورت تغییر userId:مقدار userId در سطح کامپوننت تغییر میکنه.ریکوئست برای اطلاعات کاربر جدید ارسال میشهننتیجه ش در یک signal بنام userSignal در سطح کامپوننت نگه داشته میشهبا تغییر userSignal ، دیتای جانبی postCount در کامپوننت تغییر میکنهنتیجه نهاییهمین طور که انگولار تکامل پیدا میکنه، درک عمیق این دو ابزار قدرتمند و استفاده درست ازشون میتونه منجر به تولید اپلیکیشن هایی بشه که سریع تر، سبک تر و پایدارتر رفتار میکنند.مقاله های مرتبط:آشنایی با انگولار سیگنال ، فیچر جذاب نسخه ۱۶انواع Subject در RxJSآشنایی با کتابخانه RxJSامیدوارم از این مقاله لذت ببرید و براتون مفید باشه.اگر دوست دارید میتونید از طریق صفحه لینکدین با من در ارتباط باشید :)لینک اصلی مقالهموفق باشید</description>
                <category>رهام رفیعی تهرانی</category>
                <author>رهام رفیعی تهرانی</author>
                <pubDate>Sat, 17 Aug 2024 12:23:46 +0330</pubDate>
            </item>
                    <item>
                <title>تنظیم نحوه ارسال آرایه به سرور در axios</title>
                <link>https://virgool.io/@roham.tehrani/%D8%AA%D9%86%D8%B8%DB%8C%D9%85-%D9%86%D8%AD%D9%88%D9%87-%D8%A7%D8%B1%D8%B3%D8%A7%D9%84-%D8%A2%D8%B1%D8%A7%DB%8C%D9%87-%D8%A8%D9%87-%D8%B3%D8%B1%D9%88%D8%B1-%D8%AF%D8%B1-axios-bwu2nbvgdig3</link>
                <description>چند وقت پیش یک api دستم رسید که باید در یک فیلد خاص، آرایه ای از شناسه ها رو به سمت سرور ارسال میکردم. ارسال request با axios انجام میشد ولی من تجربه کار با axios رو نداشتم. برای هماهنگ شدن کارکرد فرانت و بک مجبور شدم نیم ساعتی سرچ کنم تا به نتیجه مطمئن برسم. در این مقاله میخوام در مورد اون سرچ ساده صحبت کنم.صورت مسئلهفرض کنید یه آرایه از شناسه ها داریمconst arr=[2,3,4]قراره این شناسه ها با پارامتری بنام ids ، در ریکوئستی با متد GET ، از سمت فرانت به بک اند ارسال بشه.در مدلی که سمت بک اند پیاده سازی شده بود، انتظار میرفت آرایه ها به صورت زیر ارسال بشه:/api/something?ids=2&amp;ids=3&amp;ids=4در حالیکه به صورت پیش فرض از سمت فرانت به صورت زیر ارسال میشد:/api/something?ids[]=2&amp;ids[]=3&amp;ids[]=4توضیح کلیبه صورت کلی آرایه ای از مقادیر که به صورت GET و داخل url قراره ارسال بشه سه حالت استاندارد داره۱. حالت بدون براکت []ids=2&amp;ids=3&amp;ids=4۲. حالت با براکت بدون indexids[]=2&amp;ids[]=3&amp;ids[]=4۳. حالت با براکت و با indexids[0]=2&amp;ids[1]=3&amp;ids[2]=4یک حالت غیراستاندارد هم هست که پیشنهاد میکنم ازش اجتناب کنیدids=2,3,4با خودم فکر کردم من دارم از یک کتابخانه استاندارد، قدیمی (تکمیل شده) به غایت پرطرفدار استفاده میکنم بنام axios. بنابر این احتمالش خیلی زیاده که توسعه دهندگانش برای پشیبانی کردن از این سه حالت راه حلی ارائه داده باشند.بعد از سه چهار تا سرچ و اصلاح keyword بالاخره به جواب مورد نظرم رسیدمکتابخانه axios در پارامترهای ارسال ریکوئست خودش یک تنظیمی داره بنام paramsSerializer. داخل این تنظیم یک پراپرتی هست بنام indexes که سه تا مقدار میگیره برای سه حالت استانداردتنظیم حالت بدون براکتتنظیم حالت با براکت بدون indexتنظیم حالت با براکت با indexمقدار پیش فرض این تنظیم حالت false هست، یعنی ارسال آرایه مقادیر با براکت بدون index . بنابر این با تغییر تنظیمات axios موقع ساخت instance ، تونستم ارتباط صحیح با سرور رو برقرار کنم.امیدوارم از این مقاله لذت ببرید و براتون مفید باشه.اگر دوست دارید میتونید از طریق صفحه لینکدین با من در ارتباط باشید :)موفق باشید</description>
                <category>رهام رفیعی تهرانی</category>
                <author>رهام رفیعی تهرانی</author>
                <pubDate>Tue, 21 May 2024 21:27:08 +0330</pubDate>
            </item>
                    <item>
                <title>نمایش کامپوننت با theme های مختلف در React و NextJS</title>
                <link>https://virgool.io/@roham.tehrani/%D8%A7%D8%B6%D8%A7%D9%81%D9%87-%DA%A9%D8%B1%D8%AF%D9%86-theme-%D8%A8%D9%87-%DA%A9%D8%A7%D9%85%D9%BE%D9%88%D9%86%D9%86%D8%AA-%D8%AF%D8%B1-react-hxaps2ekuslf</link>
                <description>این چند وقته سرم حسابی شلوغه و کمتر میرسم مطالعه جانبی داشته باشم. اخیرا یک تجربه ای در حوزه NextJS داشتم که ارزش به اشتراک گذاشتن داره. اونم ارائه یک کامپوننت با چند تا تم مختلف هست. وقتی قراره به عنوان ورودی اسم یک تم رو بگیریم و بر اساس اون تم شرایط نمایش کامپوننت عوض بشه.تقریبا همه راه حل هایی که در سرچ پیدا کردم قدیمی شدند، واقعا به درد نمیخوردند و قابل پیاده سازی با TypeScript نبودند.در این روش در واقع همه چیز در abstraction مشخص میشه و داخل تابع کامپوننت فقط مقداردهی صورت میگیره.فاز اول: تعریف های abstractionفرض کنید یک کامپوننت دارم به است MyComponent که قراره با چند تا تم پیاده بشه و به عنوان ورودی یکی از تم ها رو بهش پاس بدیم.اول میام یک تایپ اضافه میکنم و متغیرهای هر تم رو مشخص میکنم:این متغیرها میتونن شامل آیکن ها یا هر رنگ و متن و عددی باشند.اگر شما هم مثل من از  tailwind  استفاده میکنین، حواستون به داینامیک کردن اسم کلاس ها در tailwind باشه.اگر لازمه مقاله داینامیک کردن اسم کلاس ها در tailwind رو مطالعه کنید.بعدش میام یک لیست از تم ها رو داخل کامپوننت مهیا میکنم:و در آخر با استفاده از keyOf type operator در typescript تایپ ورودی کامپوننت رو مشخص میکنم:فاز دوم: مقدار دهی هااول ورودی کامپوننت رو مشخص میکنماگر قبلا از این کامپوننت جاهای متعددی استفاده کردیم، میتونیم ورودی تم رو اختیاری تعریف کنیم. اگر ورودی مشخص نشه، از همون تمی استفاده میکنیم که قبلا استفاده میکردیم.مرحله دوم میام داخل کامپوننت مقدار دهی theme ها رو انجام میدم:اگر مثال اول مقاله رو ببینیم،  مشخصه که تم همیشگی مون dark هست.مرحله سوم defaultTheme و تم فعلی رو تعریف میکنم:کد بالا خوانایی بالاتری داره. کد پایین جمع و جور تره:مرحله آخر وقت تغییر خروجی کامپوننت هست:بریم کل کارهای انجام شده رو با هم ببینیم:فاز سوم: استفاده از قابلیت جدیدمیتونم به همون شکل سابق از کامپوننتم استفاده کنم:در این حالت همه چیز دقیقا مثل قبل نمایش داده میشه.یا با مشخص کردن یکی از تم ها:مشخص کنم کامپونتن با کدوم تم میخوام نمایش داده بشهموفق باشید</description>
                <category>رهام رفیعی تهرانی</category>
                <author>رهام رفیعی تهرانی</author>
                <pubDate>Sat, 11 May 2024 20:20:19 +0330</pubDate>
            </item>
                    <item>
                <title>داینامیک کردن نام کلاس ها در Tailwindcss</title>
                <link>https://virgool.io/@roham.tehrani/%D8%AF%D8%A7%DB%8C%D9%86%D8%A7%D9%85%DB%8C%DA%A9-%DA%A9%D8%B1%D8%AF%D9%86-%D9%86%D8%A7%D9%85-%DA%A9%D9%84%D8%A7%D8%B3-%D9%87%D8%A7-%D8%AF%D8%B1-tailwindcss-bbdf5kkzyafk</link>
                <description>در توسعه پروژه اخیر با Nextjs و Tailwind به یک مشکلی برخوردم که حلش یه کم زمان برد . حین جستجو برای رسیدن به راه حل، با نکته های جالبی در استفاده از Tailwindcss آشنا شدم که به نظرم ارزش دانستن داشتند. در این مقاله یکی از نکته ها رو با شما به اشتراک میگذارم.مسئله چی بود؟یه متغیر داشتم به اسم isActive از نوع boolean و یک span داشتم حاوی یک متن کوتاه.مقدار متغیر isActive مشخص میکرد که محتوای span چطوری نمایش داده بشه.اگر مقدار متغیر true بود، نوشته داخل span باید font-weight برابر با ۸۰۰ میداشت.اگر مقدارش false بود، نوشته داخل  span باید font-weight به اندازه ۴۰۰ میداشت.بنابر این کدم رو اینطوری نوشتم:وقتی پروژه اجرا میشد هیچ اتفاقی نمی افتاد. یعنی مقدار isActive تغییر میکرد ولی اصلا انگار نه انگار.داخل developer tools لیست کلاس های div رو نگاه کردم. دیدم کلاس text-[400] و text-[800] هستند ولی در css نهایی  اصلا وجود ندارند. یعنی tailwind این کلاس ها رو نساخته.علت:وقتی از Tailwind استفاده میکنیم و میخواد فایل css خودش رو بسازه، محتوای فایل های پروژه رو بر اساس تنظیمات tailwind.config.ts نگاه میکنه و هر اسم کلاسی رو که پیدا کنه به لیست نهاییش اضافه میکنه.وقتی ما اسم کلاس ها رو نصفه استاتیک و نصفه داینامیک میسازیم، Tailwind نمیتونه تشخیص بده در زمان runtime این قراره اسم کامل یک کلاس بشه و ازش عبور میکنه. در نتیجه کلاس رو به css نهاییش اضافه نمیکنه.راه حل:وقتی از Tailwind استفاده میکنیم، کلاس های داینامیک رو به شکل بالا که اسم کلاس نصفه است نباید بسازیم. اسم کامل کلاس ها رو در شرایط مختلف باید استفاده کنیم:مشکلم حل شد.در مورد ساختن اسم کلاس ها به کمک props هم همین مسئله رو باید دقت کنیم.برای ساختن اسم کلاس های داینامیک بر اساس props به صورت زیر پیاده نکنیم:میتونیم بجاش از روش زیر استفاده کنیم:لینک مقاله ای که راه حل رو داخلش پیدا کردم براتون میگذارم. پر از نکته های مفیده:https://tailwindcss.com/docs/content-configurationامیدوارم از این مقاله لذت ببرید و براتون مفید باشه.اگر دوست دارید میتونید از طریق صفحه لینکدین با من در ارتباط باشید :)موفق باشید</description>
                <category>رهام رفیعی تهرانی</category>
                <author>رهام رفیعی تهرانی</author>
                <pubDate>Mon, 15 Apr 2024 16:28:19 +0330</pubDate>
            </item>
                    <item>
                <title>تجربه من از کار با Tailwindcss</title>
                <link>https://virgool.io/codenevis/%D8%AA%D8%AC%D8%B1%D8%A8%D9%87-%D9%85%D9%86-%D8%A7%D8%B2-%DA%A9%D8%A7%D8%B1-%D8%A8%D8%A7-tailwindcss-jveghm9ie4pi</link>
                <description>طی چند وقت اخیر پروژه ای تعریف شد که روی NextJS و Tailwindcss بالا آوردیمش. برای همین مجبور شدم یک مدت تمرکزم رو از روی مطالعه انگولار بردارم و روی این پروژه متمرکز بشم. در این مقاله میخوام تجربه م رو از کار با Tailwindcss باهاتون به اشتراک بگذارم.فریم ورک Tailwindcss در واقع یک ابزار CSS هست که به برنامه نویس کمک میکنه بجای درگیر شدن با تعریف رول های CSS، یکبار Tailwindcss رو داخل پروژه ادد کنه و در ادامه مستقیما از کلاس های Tailwindcss مثل دستور استفاده کنه.برای مطالعه این framework میتونید به سایتش مراجعه کنیدhttps://tailwindcss.com/docsمزایا و معایب استفاده از Tailwindcssبه نظرم تنها عیبش اینه که HTML رو شلوغ میکنه. ولی مزیت هاش انقدر زیاده که در سیستم امروزی توسعه front با وجود کامپوننت های کوچک و کم حجم ایراد حساب نمیشه. برای رفع این عیب، پروژه ای ساخته شده بنام daisyUI که founder ش یک ایرانیه. این پروژه بر روی Tailwind تعریف شده. اگر daisyUI رو به اپ اضافه کنین، خیلی از کلاس هایی که به صورت یکجا و با هم نیاز داریم در قالب یک کلاس تعریف شده اند. (مثلا button ها ، tab ها و ... ) بعلاوه اینکه همچنان میشه کنارش از امکانات Tailwind استفاده کرد.لینک زیر رو ببینید:https://react.daisyui.com/?path=/docs/welcome--docs مهمترین مزیت Tailwindcss که به چشم من اومد، اینه که سرعت تعریف رول های CSS رو بالا میبره. امروزه بیشتر IDE ها از نوشتن کدهای HTML با روش های سریع پشتیبانی میکنند. در واقع با نوشتن پشت سر هم دستور زیر و فشاردادن دکمه enter، یک المنت کامل ساخته میشهبدون اینکه هیچ رفت و برگشتی بین فایل های HTML و CSS اتفاق بیفته، و بدون اینکه دست برنامه نویس از کیبورد جدا بشه، یک المنت با همه رول های CSS ساخته میشه.مزیت مهم دیگه ش به نظر من اینه که یک زبان مشترک بین برنامه نویس ها حساب میشه و learning curve کمتری نسبت به یک UIKit اختصاصی داره که شما برای پروژه یا پروژه هاتون با دیگران به اشتراک بگذارید.یه مزیت دیگه ش اینه که در پروژه شاهد اسم گذاری های بی معنی، مسخره و طولانی برای کلاس های CSS نیستیم. اسم کلاس ها کوتاه و با معنی مشخص هستند.آخرین مزیتش رو بخوام بگم، همه تغییرات به داخل layout ها محدود میشه. تغییرات داخل layout رو به هر نحوی که بخوایم میتونیم پیاده سازی کنیم. و همچنین شاهد کمترین حجم CSS لازم برای کد هستیم.ساختن یک پروژه به همراه Tailwindcssاول یک پروژه خالی میسازیمبرای اینکه Tailwind رو به پروژه اضافه کنیم، اول باید پکیجش رو نصب کنیم.مرحله سوم ساختن فایل تنظیمات Tailwindcss است. با اجرای دستور زیر:فایلی بنام tailwind.config.js داخل پروژه ساخته میشه.در این فایل میتونید انواع تنظیمات مورد نیازتون رو وارد کنید. فعلا، داخل فایل تنظیم در بخش content ، تنظیمی رو اضافه کنین که فایل های حاوی CSS های Tailwindcss رو شامل بشه:بعد یک فایل بنام styles.css درست کنید و خطوط زیر رو داخلش بنویسید تا کدهای Tailwindcss رو به CSS اضافه کنه.با اجرای دستور زیر، یک فایل output.css ساخته میشه که شامل همه رول های CSS مورد نیازمون هست:فایل ساخته شده output.css رو میتونیم هر جای پروژه که خواستیم استفاده کنیم.این دستور یک ورودی watch هم داره که به محض تغییر فایل CSS خودش خروجی رو دوباره میسازه.امیدوارم از این مقاله لذت ببرید و براتون مفید باشه.اگر دوست دارید میتونید از طریق صفحه لینکدین با من در ارتباط باشید :)موفق باشید</description>
                <category>رهام رفیعی تهرانی</category>
                <author>رهام رفیعی تهرانی</author>
                <pubDate>Thu, 11 Apr 2024 15:51:40 +0330</pubDate>
            </item>
                    <item>
                <title>حل مسئله تقسیم با تاخیر در مصاحبه فنی</title>
                <link>https://virgool.io/codenevis/%D8%AD%D9%84-%D9%85%D8%B3%D8%A6%D9%84%D9%87-%D8%AA%D9%82%D8%B3%DB%8C%D9%85-%D8%A8%D8%A7-%D8%AA%D8%A7%D8%AE%DB%8C%D8%B1-%D8%AF%D8%B1-%D9%85%D8%B5%D8%A7%D8%AD%D8%A8%D9%87-%D9%81%D9%86%DB%8C-vfyewkhsyxyz</link>
                <description>نزدیک به یک ماه پیش، یک نوشته ای در لینکدین مطالعه کردم که برام جالب بود. یکی از برنامه نویس های حرفه ای اینطوری بیان کرده که صورت مسئله ای رو مطرح کرده و به صد نفر در مصاحبه های فنی داده و خواسته که حلش کنند. این همکار عزیز گفته بود فقط ۵ نفر تونستند مسئله رو حل کنند!نکته ای که برا من جالب بود، عمیق بودن مسئله است. و همون موقع گفتم راجع به راه حلش یک مقاله مینویسم. مسئله پر از نکته هاییه که همه رو باید با هم جمع کرد تا به صورت مسئله رسید.نکته مهم تر طرز فکر ما برای حل مسئله است. خواستم با این مقاله، هم راه حل رو بگم و هم طرز فکر خودم رو برای حل مسئله باهاتون به اشتراک بگذارم.بریم ببینیم صورت مسئله چیه:با توجه به نکات زیر یک تابع بنویسید که دو عدد از ورودی دریافت کند و حاصل تقسیم را محاسبه نماید و خروجی را برگرداند.۱. هروگونه خطا را هندل کنید.۲. تابع با ۳ ثانیه تاخیر خروجی را برگرداند.۳. تابع را از بیرون صدا بزنید و از async و await استفاده کنید.پیشنهاد میکنم قبل از اینکه راه حل رو ببینید، خودتون یک بار سعی کنید مسئله رو حل کنید.بریم مسئله رو قدم به قدم حل کنیم.قدم اولاولین نکته ای که بهش توجه کردم نکته سوم صورت مسئله بود.۳. تابع را از بیرون صدا بزنید و از async و await استفاده کنید.یعنی داخل تابع از Promise استفاده میکنم و فرمت تابع همچین چیزیه:قدم دومشرط اول صورت مسئله چی میگه؟۱. هرگونه خطا را هندل کنیدبنابراین باید تابع داخل try cache نوشته بشه:و همچنین میتونه به این معنی باشه که همه ورودی ها رو به ازای خطاهای قابل پیش بینی بررسی کنیم. چه خطاهایی قابل پیش بینی هستند؟۱. ورودی های a و b عدد نباشند.۲.  مقدار ورودی b صفر باشه که منجر به خطای divide by zero میشه.با هندل کردن این خطاهای قابل پیش بینی، به کد زیر میرسیم:قدم سومحالا میرسیم به نکته دوم:۲. تابع با ۳ ثانیه تاخیر خروجی را برگرداند.برای تاخیر در ارائه جواب باید از تابع setTimeout استفاده کنیم.قدم چهارمبه نظر میرسه تابع ما آماده شده و طبق نکته سوم، باید از بیرون با async و await صدا بزنیم:اما یه نکته ای باقی مونده. ما یک تابع ساختیم که تابع divide رو صدا بزنه. ولی خودش رو اجرا نکردیم. پس خود تابع رو هم صدا میکنیم. به این تکنیک در جاوااسکریپت IIFE میگن:قدم پنجمکد نهایی رو در یک فایل بنام divide.js ذخیره میکنیم.با اجرای دستور زیر اجراش میکنیم:و خروجی عدد ۵ رو میبینیم.قدم ششموقتی تابع رو با مقادیر a=10 و b=0 اجرا کنیم همچین خطایی میگیریم:بنابر این با توجه به نکته اول (هرگونه خطا را هندل کنید) ، دستورات صدا زدن تابع divide رو صورت زیر تغییر میدیم:و عبارت زیر در کنسول لاگ میشه:در واقع ما همه خطاها رو هندل کردیم.جالب اینه که قدم ششم در راه حل خود مطرح کننده سوال هم نبود!امیدوارم از این مقاله لذت ببرید و براتون مفید باشه.اگر دوست دارید میتونید از طریق صفحه لینکدین با من در ارتباط باشید :)</description>
                <category>رهام رفیعی تهرانی</category>
                <author>رهام رفیعی تهرانی</author>
                <pubDate>Wed, 27 Mar 2024 12:59:33 +0330</pubDate>
            </item>
                    <item>
                <title>آشنایی با module resolution در انگولار</title>
                <link>https://virgool.io/codenevis/%D8%A2%D8%B4%D9%86%D8%A7%DB%8C%DB%8C-%D8%A8%D8%A7-module-resolution-%D8%AF%D8%B1-%D8%A7%D9%86%DA%AF%D9%88%D9%84%D8%A7%D8%B1-i5d4udrvars2</link>
                <description>در انگولار چطوری ماژول های مورد نیازتون رو import میکنید؟به صورت relative ؟یا به صورت absolute ؟فرض کنید پروژه بزرگی دارید و در همه ماژول ها، import ها به صورت absolute یا relative آدرس دهی شده اند.حالا قصد دارید مثلا بخش shared داخل پروژه رو جابجا کنید و به مکان جدیدی منتقل کنید. همه ماژول هایی که از یک فایل داخل پوشه shared استفاده کردند، باید آدرس های relative یا absolute خودشون رو تغییر بدن.حتی با پشتیبانی IDE از تغییر آدرس ها، باز هم تغییر مناسب آدرس ها در یک پروژه بزرگ، زمان و تمرکز ویژه ای رو می طلبه.اینجاست که راه حل module resolution به کار میاد.داخل فایل tsconfig.json در بخش compilerOptions  یک attribute خاص داریم به اسم paths که به صورت پیش فرض تعریف نشده و باید تعریفش کنید:با تعریف های جدید حالا میتونیم بخش های مختلف سیستم رو به صورت زیر import کنیم:با این روش، هزینه تغییر مسیر هر ماژول یا بخش از پروژه با هزینه بسیار کمتری انجام میشه. فقط کافیه یک تنظیم مربوط به اون بخش یا ماژول داخل فایل tsconfig.json به روز رسانی بشه.امیدوارم از این مقاله لذت ببرید و براتون مفید باشه.اگر دوست دارید میتونید از طریق صفحه لینکدین با من در ارتباط باشید :)</description>
                <category>رهام رفیعی تهرانی</category>
                <author>رهام رفیعی تهرانی</author>
                <pubDate>Tue, 19 Mar 2024 19:52:06 +0330</pubDate>
            </item>
                    <item>
                <title>دانلود خروجی اکسل در انگولار</title>
                <link>https://virgool.io/@roham.tehrani/%D8%AF%D8%A7%D9%86%D9%84%D9%88%D8%AF-%D8%AE%D8%B1%D9%88%D8%AC%DB%8C-%D8%A7%DA%A9%D8%B3%D9%84-%D8%AF%D8%B1-%D8%A7%D9%86%DA%AF%D9%88%D9%84%D8%A7%D8%B1-nzvrrmogej7m</link>
                <description>چند وقت پیش یک تسکی برام تعریف شد که باید با کلیک روی یک دکمه، ریکوئست به سرور میزدم و دیتای برگشتی از سرور رو به صورت خروجی اکسل دانلود میکردم. در این مقاله سعی میکنم همین کار رو قدم به قدم در قالب یک پروژه مجزا توضیح بدم.مرحله اول: ساخت اپلیکیشن تستی به همراه پکیج xlsxاول از همه یک پروژه جدید تعریف میکنم به اسم xlsx:حالا باید پکیج xlsx رو هم روی پروژه نصب کنم:از بالا اومدن پروژه مطمئن میشم:وقتی پروژه رو روی loacalhost:4200 ( آدرس پیشفرض پروژه روی لوکال ) دیدم به بقیه کار ادامه میدم. مرحله دوم: نمایش آیکن دانلود و تعریف شروع فرایندیک تابع کال بک برای شروع فرایند دانلود گزارش در فایل app.component.ts تعریف میکنم:اسم تابع رو exportClickHandler گذاشتم.حالا یک آیکن برای دانلود در فایل app.component.html به ظاهر پروژه اضافه میکنم و کال بک رو به click event ش اضافه میکنم:با کلیک روی آیکن باید متن clicked رو در کنسول ببینم. با دیدن متن مورد نظر به مرحله بعدی میرم:مرحله سوم: ارسال ریکوئست و دریافت دیتابه کامپوننت app.component.ts یک آبجکت از httpClient انگولار رو inject میکنم تا بتونم ریکوئست بفرستم و بگیرم:و البته اضافه کردن HttpClientModule به app.module.tsحالا یک API پابلیک روی وب انتخاب میکنم و بهش درخواست ارسال میکنم و چک میکنم جوابش رو دریافت کنم. api که من انتخاب کردم یک لیست از post های مختلف رو میفرسته. روش کار قدیمی یا جدیدش فرقی نمیکنه. میخوایم به دانلود اکسل برسیم:با کلیک روی آیکن دانلود جواب api رو داخل کنسول میبینیم و میتونیم برسیم به قسمت اصلیمرحله چهارم: نگهداری دیتای دریافت شده داخل یک آرایه در کلاساول یک interface به اسم Post داخل فایلی بنام post.ts تعریف کردم:این interface رو داخل app.component.ts ایمپورت کردم و یک متغیر داخل کلاس تعریف کردم بنام postList که لیست پست های دریافت شده رو داخلش قرار بدم:حالا دریافت دیتای api رو به صورت زیر تغییر دادم:حالا چطوری از طریق کنسول ببینم آیا متغیرمون پر شده یا نه؟اول  روی آیکن دانلود کلیک میکنم. بعدش:داخل صفحه یک آیکن داریم و دیگر هیچ. پس با دستور زیر به DOM node آیکن داخل صفحه میرسم:با اجرای دستور زیر به AppComponent میرسم ( کامپوننتی که حاوی node آیکنم هست):درسته که در جواب کنسول دارم postList رو می بینم. ولی اگر تعداد متغیرها زیاد بود، با صدا کردن property مورد نظر از آبجکت کامپوننت، میتونم محتوای داخلش رو ببینم:حالا که لیست post هامون پر شده و دیتا رو داخل کامپوننت نگه میدارم، میرم سراغ مرحله بعد:مرحله ششم: ساخت یک جدول پنهان در ظاهر پروژهیک جدول داخل صفحه app.component.html تعریف کردم و دیتا ها رو بهش پاس دادم:برای پنهان کردنش راه های مختلفی هست. من با اضافه کردن استایل های زیر به app.component.scss این کار رو انجام دادم:حالا بریم برای بخش نهایی و استفاده از پکیج xlsx.مرحله هفتم: استفاده از پکیج xlsx و دانلود خروجیاول پکیج xlsx رو به صورت زیر داخل app.component.ts ایمپورت میکنم:حجم پکیج 420.3k هست که به صورت gzipped میرسه به 138.6k. نسبتا پکیج بزرگی هست.وقتی لیست پست های دریافتی از api رو به آرایه postList پاس میدم، هیچ render خاصی روی صفحه انجام نشده. بنابر این به کمک setTimeout ، اجرای کد رو به بعد از رندر مجدد صفحه در event loop موکول میکنم:به محض اجرای مجدد اپلیکیشن و کلیک رو دکمه دانلود، یک فایل به اسم Posts.xlsx دانلود میشه و تمااااممم.امیدوارم از این مقاله لذت ببرید و براتون مفید باشه.اگر دوست دارید میتونید از طریق صفحه لینکدین با من در ارتباط باشید :):)</description>
                <category>رهام رفیعی تهرانی</category>
                <author>رهام رفیعی تهرانی</author>
                <pubDate>Wed, 14 Feb 2024 21:16:57 +0330</pubDate>
            </item>
                    <item>
                <title>آشنایی با micro task queue در javascript</title>
                <link>https://virgool.io/@roham.tehrani/%D8%A2%D8%B4%D9%86%D8%A7%DB%8C%DB%8C-%D8%A8%D8%A7-micro-task-queue-%D8%AF%D8%B1-javascript-myw9zyrks9et</link>
                <description>بیاید با یک مثال شروع کنیم. به نظرتون خروجی کد زیر کدوم گزینه است؟اگر با جاوا اسکریپت و event loop آشنا باشید میتونید که گزینه a نیست. جواب بین گزینه b و c هست.اگر با micro task queue آشنا باشید میدونید چرا جواب c درسته و b غلط.بریم تحلیلش کنیم:اول از همه که عدد 1 پرینت میشه. عدد 2 در setTimeout هست و asynchronous اجرا میشه . بنابراین بلافاصله پرینت نمیشه و به task queue میره. بعدش عدد 3 پرینت میشه. promise ها هم asyncronous هستند. پس اجرای promise هم به task queue میره (!). بعد عدد 5 پرینت میشه.به نظر میرسه که باید عدد 2 پرینت بشه و بعدش عدد 4. در حالیکه با اجرای این کد میبینیم که اول عدد 4 اجرا میشه و بعد عدد 2.چرا ؟جوابش به ساختار جاوااسکریپت در اجرای دستورات برمیگرده. Promise ها در صفی ذخیره میشوند بنام micro task queue. اعضای این صف بعد از اجرای همه callback های یک event، و قبل از اینکه جاوااسکریپت event loop را بررسی کند، اجرا میشوند. در واقع اعضای این صف با اولویت بالاتری اجرا میشوند.در واقع بعد از اجرای console.log(5) ، اجرای اسکریپت فعلی تمام میشه و وقتشه جاوااسکریپت به صف task ها سر بزنه. ولی اول به micro task queue سر میزنه و میبینه یک Promise هست که باید صدا زده بشه.بنابر این اول عدد ۴ اجرا میشه. event loop همچنان به micro queue task نگاه میکنه و تا زمانی که خالی نباشه سراغ task queue نمیره. با اجرای عدد ۴ و خالی شدن micro queue task ، حالا به سراغ task های عادی میره و console.log(2) رو اجرا میکنه.بریم یک مثال دیگه ببینیم:در این کد چه اتفاقی می افته؟ لطفا یک دور خودتون سعی کنین تحلیل کنین و بعد بیاین سراغ اتفاقی که واقعا می افته.قدم اول: نوبت به اجرای اسکریپت اصلی توسط event loop میرسه. اسکریپت اصلی به stack میره و اجراش شروع میشه.قدم دوم: callback اول برای کلیک روی دکمه رجیستر میشه.قدم سوم: callback دوم برای کلیک روی دکمه رجیستر میشه.قدم چهارم: روی دکمه کلیک میشه و callback اول جهت اجرا شدن به stack میره.دقت کنید که الان داخل stack هم اسکریپت اصلی رو داریم و هم callback اول رو داریم. تا وقتی button.click تموم نشه ، اسکریپت ما در حال اجراست.قدم پنجم: دستور لاگ کردن Microtask1 میره در micro task queue میشینهقدم ششم: دستور لاگ کردن Listener 1 اجرا میشه.قدم هفتم و مهم ترین قسمت : اجرای callback اول تموم میشه و بر میگرده به اسکریپت اصلی.قدم هشتم: callback دوم برای اجرا فراخوانی میشه و به stack میره.قدم نهم: دستور لاگ کردن Microtask 2 میره در micro task queue میشینه.قدم دهم: دستور لاگ کردن Listener 2 اجرا میشه.قدم یازدهم: اجرای callback دوم هم تموم میشه و برمیگرده به اسکریپت اصلی.قدم دوازدهم: اجرای button.click تموم میشه و به دنبالش اجرای اسکریپت اصلی تموم میشه.قدم سیزدهم: قبل از اینکه سراغ task ها بره، میره سراغ micro task queue. داخل micro task queue یک task پیدا میکنه و دستور لاگ کردنMicrotask 1 رو اجرا میکنه.قدم چهاردهم: هنوز micro task queue خالی نشده. پس task بعدیش رو اجرا میکنه و دستور لاگ کردن Microtask 2 رو اجرا کنه.قدم پانزدهم: micro task queue خالی شده. پس میره سراغ task queue و باز هم چیزی نمی بینه و اجرای کد تموم میشه.قدم شانزدهم: event loop همچنان منتظره تا رویداد جدیدی ثبت بشه.خروجی :Listener 1, Listener 2, Microtask 1, Microtask 2مقاله های مرتبط:تفاوت stopPropagation و stopImmediatePropagationامیدوارم از این مقاله لذت ببرید و براتون مفید باشه.اگر دوست دارید میتونید از طریق صفحه لینکدین با من در ارتباط باشید :)</description>
                <category>رهام رفیعی تهرانی</category>
                <author>رهام رفیعی تهرانی</author>
                <pubDate>Wed, 31 Jan 2024 15:02:48 +0330</pubDate>
            </item>
            </channel>
</rss>