بهینه‌سازی (۳) – فراخوانی مکرر یک تابع

شروع موضوع توسط yaa110 ‏24 جولای 2013 در انجمن برنامه فلش Flash

کلمات کلیدی:
  1. yaa110

    yaa110 کاربر فعال

    ارسال‌ها:
    206
    تشکر شده:
    507
    امتیاز دستاورد:
    16
    در بخش سوم از مجموعه بهینه سازی :ف: و :ا: به معرفی Recursion می پردازیم. Recursion عبارت است از فراخوانی یک تابع در انتهای کدهای همان تابع با هدف تکرار تابع مفروض و ایجاد یک حلقه توسط تابع مفروض. خروجی نهایی این عملیات مشابه با حلقه for می باشد که در بخش اول توضیح داده شد. اما در عمل و اصول پردازش حلقه for و فراخوانی مکرر توابع تفاوت هایی وجود دارد که در ادامه به آنها می پردازیم.


    • نحوه فراخوانی توابع در Flash Player و Air Debugger
    تمامی توابع بعد از فراخوانی توسط کدنویس به صف فراخوانی یا Call Stack منتقل می شوند و سپس در فاز اول هر حلقه تمامی توابع موجود در صف فراخوانی یکی یکی پردازش می شوند. در ادامه هریک از توابعی که کامل پردازش شد از صف فراخوانی حذف خواهد شد. مثال زیر را در نظر بگیرید:

    [در صورت عدم مشاهده کد به صورت صحیح، به سایت منبع مراجعه کنید]

    کد (Text):
    [/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 مواجه خواهید شد. این خطا زمانی ارسال می شود که تعداد زیادی تابع در صف فراخوانی قرار بگیرد و دیگر جایی برای توابع بعدی نباشد (مانند زمانی که یک لیوان آب سرریز می شود). با بروز این خطا، عملیات پردازش متوقف خواهد شد و اپلیکیشن از کار می افتد.


    • استفاده از روش ارسال خطا برای جلوگیری از خطای سرریز
    برای جلوگیری از بروز خطای سرریز، می توانیم با استفاده از تعریف یک Listener برای رویداد enterFrame و یک تابع محافظ، تعداد مراحل فراخوانی مکرر تابع مفروض را در فاز اول هر حلقه فریم کنترل کنیم. به مثال زیر توجه کنید:

    [در صورت عدم مشاهده کد به صورت صحیح، به سایت منبع مراجعه کنید]

    کد (Text):
    [/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 مشخص است بعد از هر بار ارسال خطا صف فراخوانی بازسازی می شود و توابع مشابهی که قبلا فراخوانی و کاملا اجرا شده اند در صف فراخوانی نخواهند بود.

    [​IMG]
    شکل1. نحوه پردازش توابع مکرر و خالی شدن (بازسازی) صف فراخوانی (Call stack). [منبع: senocular.com]​

    نکته:
    در نوشتن تابع process، حتما دقت کنید که اولویت قرار گرفتن کدها بسیار مهم است. در بهترین حالت این اولویت از بالا به پایین می تواند به صورت زیر باشد:
    1- اجرای کدهای عملیاتی
    2- بررسی ادامه یا عدم ادامه کل حلقه تکرار تابع
    3- بررسی نیاز به خروج از فاز اول و وارد شدن به حلقه فریم جدید (needToExit )
    4- فراخوانی مجدد تابع
    توجه:
    درصورتیکه با مفاهیم مربوط به تعداد فاز در هر فریم و سایر اصطلاحات آشنا نیستید، بخش اول از مجموعه بهینه سازی را مطالعه کنید.

    منبع: http://flashcenter.ir/fa/1392/05/02/بهینه‌سازی-3-فراخوانی-مکرر-یک-تابع/
     
    نوشته شده توسط yaa110 در ‏24 جولای 2013
    r.miri19، ++Hadi++ و m0hsen.a از این ارسال تشکر کرده اند.

به اشتراک بگذارید