yaa110
کاربر فعال
در بخش سوم از مجموعه بهینه سازی :ف: و :ا: به معرفی Recursion می پردازیم. Recursion عبارت است از فراخوانی یک تابع در انتهای کدهای همان تابع با هدف تکرار تابع مفروض و ایجاد یک حلقه توسط تابع مفروض. خروجی نهایی این عملیات مشابه با حلقه for می باشد که در بخش اول توضیح داده شد. اما در عمل و اصول پردازش حلقه for و فراخوانی مکرر توابع تفاوت هایی وجود دارد که در ادامه به آنها می پردازیم.
[در صورت عدم مشاهده کد به صورت صحیح، به سایت منبع مراجعه کنید]
در این مثال، تابع process، مدام توسط خود تابع مجددا فراخوانی می شود تا یک حلقه شامل 10000 مرحله را تشکیل دهد. درصورتی که این دستور را اجرا کنید، بعد از گذشت چند مرحله (بستگی به مشخصات سخت افزاری هم دارد) با خطای Stack overflow occurred مواجه خواهید شد. این خطا زمانی ارسال می شود که تعداد زیادی تابع در صف فراخوانی قرار بگیرد و دیگر جایی برای توابع بعدی نباشد (مانند زمانی که یک لیوان آب سرریز می شود). با بروز این خطا، عملیات پردازش متوقف خواهد شد و اپلیکیشن از کار می افتد.
[در صورت عدم مشاهده کد به صورت صحیح، به سایت منبع مراجعه کنید]
تابع needToExit: در این مثال تابع needToExit همان تابع محافظ است که کنترل کننده تعداد دفعات تکرار تابع مفروض (process) می باشد. طبق کد نوشته شده در تابع needToExit بعد از هر 20 بار تکرار، حلقه فریم تکرار خواهد شد. تعیین مقدار breakStep (در اینجا 20) نیازمند شناخت عملیات هایی است که در هر مرحله انجام می شود، بنابراین برای تعیین آن نیاز به سعی و خطا و تجربه دارید (روش مشخصی برای تعیین دقیق این متغیر پیدا نکردم). زمانیکه موعد پایان فاز اول هر حلقه فریم فرا برسد (یعنی مقدار true توسط تابع needToExit ارسال شود)، یک خطا ارسال (throw) خواهد شد که می تواند نوع و متن دلخواه داشته باشد (در این مثال یک شی از نوع کلاسه Error ایجاد و ارسال شده است). ارسال این خطا موجب توقف ادامه پردازش تابع process و همچنین خالی شدن Call Stack خواهد شد. در شکل1 نحوه پردازش توابع مکرر به صورت شماتیک آمده است. همانطور که در شکل1 مشخص است بعد از هر بار ارسال خطا صف فراخوانی بازسازی می شود و توابع مشابهی که قبلا فراخوانی و کاملا اجرا شده اند در صف فراخوانی نخواهند بود.
نکته: در نوشتن تابع process، حتما دقت کنید که اولویت قرار گرفتن کدها بسیار مهم است. در بهترین حالت این اولویت از بالا به پایین می تواند به صورت زیر باشد:
1- اجرای کدهای عملیاتی
2- بررسی ادامه یا عدم ادامه کل حلقه تکرار تابع
3- بررسی نیاز به خروج از فاز اول و وارد شدن به حلقه فریم جدید (needToExit )
4- فراخوانی مجدد تابع
توجه: درصورتیکه با مفاهیم مربوط به تعداد فاز در هر فریم و سایر اصطلاحات آشنا نیستید، بخش اول از مجموعه بهینه سازی را مطالعه کنید.
منبع: http://flashcenter.ir/fa/1392/05/02/بهینهسازی-3-فراخوانی-مکرر-یک-تابع/
- نحوه فراخوانی توابع در Flash Player و Air Debugger
[در صورت عدم مشاهده کد به صورت صحیح، به سایت منبع مراجعه کنید]
کد:
[/I]var indexSaved:int = 0;
process();
function process():void {
// Start of Actions
trace(indexSaved);
// End of Actions
indexSaved += 1;
if (indexSaved < 10000) {
process();
}
}[I]
در این مثال، تابع process، مدام توسط خود تابع مجددا فراخوانی می شود تا یک حلقه شامل 10000 مرحله را تشکیل دهد. درصورتی که این دستور را اجرا کنید، بعد از گذشت چند مرحله (بستگی به مشخصات سخت افزاری هم دارد) با خطای Stack overflow occurred مواجه خواهید شد. این خطا زمانی ارسال می شود که تعداد زیادی تابع در صف فراخوانی قرار بگیرد و دیگر جایی برای توابع بعدی نباشد (مانند زمانی که یک لیوان آب سرریز می شود). با بروز این خطا، عملیات پردازش متوقف خواهد شد و اپلیکیشن از کار می افتد.
- استفاده از روش ارسال خطا برای جلوگیری از خطای سرریز
[در صورت عدم مشاهده کد به صورت صحیح، به سایت منبع مراجعه کنید]
کد:
[/FONT][/COLOR]import flash.events.Event;
var indexSaved:int = 0;
var breakStep:int = 20;
addEventListener(Event.ENTER_FRAME, onEnterFrame);
function onEnterFrame(e:Event):void {
try {
process();
} catch (e:Error) {
trace("New Chunk");
}
}
function process():void {
// Start of Actions
trace(indexSaved);
// End of Actions
if (indexSaved < 10000) {
indexSaved += 1;
} else {
removeEventListener(Event.ENTER_FRAME, onEnterFrame);
trace ("Finished.");
}
if (needToExit()) {
throw new Error("Application needs a break ...");
}
process();
}
function needToExit():Boolean {
if ((indexSaved % breakStep == 0) && (indexSaved != 0)) {
return true;
} else {
return false;
}
}[COLOR=#333333][FONT=Georgia]
تابع needToExit: در این مثال تابع needToExit همان تابع محافظ است که کنترل کننده تعداد دفعات تکرار تابع مفروض (process) می باشد. طبق کد نوشته شده در تابع needToExit بعد از هر 20 بار تکرار، حلقه فریم تکرار خواهد شد. تعیین مقدار breakStep (در اینجا 20) نیازمند شناخت عملیات هایی است که در هر مرحله انجام می شود، بنابراین برای تعیین آن نیاز به سعی و خطا و تجربه دارید (روش مشخصی برای تعیین دقیق این متغیر پیدا نکردم). زمانیکه موعد پایان فاز اول هر حلقه فریم فرا برسد (یعنی مقدار true توسط تابع needToExit ارسال شود)، یک خطا ارسال (throw) خواهد شد که می تواند نوع و متن دلخواه داشته باشد (در این مثال یک شی از نوع کلاسه Error ایجاد و ارسال شده است). ارسال این خطا موجب توقف ادامه پردازش تابع process و همچنین خالی شدن Call Stack خواهد شد. در شکل1 نحوه پردازش توابع مکرر به صورت شماتیک آمده است. همانطور که در شکل1 مشخص است بعد از هر بار ارسال خطا صف فراخوانی بازسازی می شود و توابع مشابهی که قبلا فراخوانی و کاملا اجرا شده اند در صف فراخوانی نخواهند بود.

شکل1. نحوه پردازش توابع مکرر و خالی شدن (بازسازی) صف فراخوانی (Call stack). [منبع: senocular.com]
نکته: در نوشتن تابع process، حتما دقت کنید که اولویت قرار گرفتن کدها بسیار مهم است. در بهترین حالت این اولویت از بالا به پایین می تواند به صورت زیر باشد:
1- اجرای کدهای عملیاتی
2- بررسی ادامه یا عدم ادامه کل حلقه تکرار تابع
3- بررسی نیاز به خروج از فاز اول و وارد شدن به حلقه فریم جدید (needToExit )
4- فراخوانی مجدد تابع
توجه: درصورتیکه با مفاهیم مربوط به تعداد فاز در هر فریم و سایر اصطلاحات آشنا نیستید، بخش اول از مجموعه بهینه سازی را مطالعه کنید.
منبع: http://flashcenter.ir/fa/1392/05/02/بهینهسازی-3-فراخوانی-مکرر-یک-تابع/