به نام خدا با عرض سلام وخسته نباشید خدمت دوستان عزیز و بزرگوار در این مقاله در مورد Memoization در جاوا اسکریپت صحبت خواهیم کرد، یک تکنیک بهینهسازی که میتواند به کارآمدتر کردن فرآیندهای محاسباتی سنگین کمک کند.با ما همراه باشید.
ما در مورد Memoization چیست؟ و بهترین زمان اجرای آن صحبت خواهیم کرد. در ادامه مثال های عملی برای جاوا اسکریپت و ری اکت خواهیم اورد.
Memoization چیست؟
در برنامه نویسی، Memoization یک تکنیک بهینه سازی است که برنامه ها را کارآمدتر و در نتیجه سریعتر می کند. این کار را با ذخیره نتایج محاسباتی در حافظه پنهان انجام میدهد. و دفعه بعد به جای محاسبه مجدد، همان اطلاعات را از حافظه نهان که به آن نیاز داریم را، بازیابی میکند.
به عبارت سادهتر، شامل ذخیره کردن خروجی یک تابع در حافظه نهان و بررسی اینکه آیا در هر اجرا محاسبات مورد نیاز قبل از محاسبه در حافظه پنهان موجود است یا خیر.
کش صرفاً یک ذخیرهسازی موقت داده است که دادهها را نگه میدارد تا درخواستهای آینده برای آن دادهها سریعتر ارائه شوند.
Memoization یک ترفند ساده اما قدرتمند است که می تواند به سرعت بخشیدن به کد ما کمک کند، مخصوصاً وقتی با عملکردهای محاسباتی تکراری و سنگین سروکار داریم.
Memoization چگونه کار می کند؟
مفهوم Memoization در جاوا اسکریپت بر دو مفهوم متکی است:
- Closures
- Higher Order Functions
نمونه Memoization جاوا اسکریپت
برای روشن تر شدن موضوع از مثال کلاسیک دنباله فیبوناچی استفاده می کنیم.
دنباله فیبوناچی مجموعهای از اعداد است که با یک یا صفر شروع میشود و به دنبال آن یک میآید و بر اساس این قانون پیش میرود که هر عدد (که عدد فیبوناچی نامیده میشود) برابر با مجموع دو عدد قبلی است.
1 |
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, … |
فرض کنید باید تابعی بنویسیم که عنصر n را در دنباله فیبوناچی برگرداند. با دانستن اینکه هر عنصر حاصل جمع دو عنصر قبلی است، یک راه حل بازگشتی می تواند به صورت زیر باشد:
1 |
const fib = n => { if (n <= 1) return 1 return fib(n - 1) + fib(n - 2) } |
اگر با بازگشت آشنا نیستید، این به سادگی مفهوم تابعی است که خود را فراخوانی می کند، با نوعی حالت پایه برای جلوگیری از یک حلقه بی نهایت (دراین مثال if (n <= 1)).
اگر تابع خود را مانند fib(5) صدا بزنیم، در پشت صحنه تابع ما به صورت زیر اجرا می شود:
ببینید که ما چندمین بار fib(0)، fib(1)، fib(2) و fib(3) را اجرا می کنیم. خب، این دقیقاً همان نوعی است که Memoization به حل آن کمک می کند.
با Memoization ، نیازی به محاسبه مجدد مقادیر یکسان نیست – ما فقط هر محاسبات را ذخیره می کنیم و در صورت نیاز دوباره همان مقدار را برمی گردانیم.
با پیاده سازی memoization ، عملکرد ما به شکل زیر خواهد بود:
1 2 3 4 5 6 7 |
const fib = (n, memo) => { memo = memo || {} if (memo[n]) return memo[n] if (n <= 1) return 1 return memo[n] = fib(n-1, memo) + fib(n-2, memo) |
کاری که ما در ابتدا انجام می دهیم این است که بررسی کنیم آیا شی memo را به عنوان پارامتر دریافت کرده ایم یا خیر. اگر این کار را نکردیم، آن را به عنوان یک شی خالی تنظیم می کنیم:
1 |
memo = memo || {} |
سپس، بررسی می کنیم که آیا memo حاوی مقداری است که به عنوان پارامتر در کلیدهای خود دریافت کرده ایم؟ اگر این چنین باشد، مقدار آن را برمی گردانیم. اینجا جایی است که جادو اتفاق می افتد. هنگامی که مقدار خود را در memoذخیره کردیم، نیازی به بازگشت بیشتر نمیباشد.
1 |
if (memo[n]) return memo[n] |
اگر هنوز مقدار را در memo نداشته باشیم، دوباره fib را فراخوانی میکنیم، اما اکنون memo را بهعنوان پارامتر ارسال میکنیم، بنابراین توابعی که ما فراخوانی میکنیم همان مقادیر حافظهگذاریشدهای را که در تابع “اصلی” داریم به اشتراک خواهند گذاشت. توجه داشته باشید که نتیجه نهایی را قبل از برگرداندن کش به حافظه پنهان اضافه می کنیم.
1 |
return memo[n] = fib(n-1, memo) + fib(n-2, memo) |
و بس! با دو خط کد، memoization را پیاده سازی کرده ایم و عملکرد خود را به طور قابل توجهی بهبود بخشیده ایم!
خب دوستان عزیز به پایان مقاله Memoization چیست؟ رسیدیم امیدواریم مورد توجه شما قرار گرفته شده باشد.
پیروز و سربلند باشید.
سایرمقالات :
تفاوتهای Object و Map در جاوااسکریپت
پیاده سازی کتابخانه data binding در اندروید به چه صورتی میباشد ؟
دیدگاهتان را بنویسید