API requestAnimationFrame - اکنون با دقت زیر میلی ثانیه

Ilmari Heikkinen

اگر از requestAnimationFrame استفاده می‌کردید، از دیدن رنگ‌هایتان با نرخ تازه‌سازی صفحه همگام شده‌اند، که منجر به با کیفیت‌ترین انیمیشن‌های ممکن می‌شود. به‌علاوه، وقتی کاربران به تب دیگری می‌روند، صدای فن CPU و انرژی باتری را ذخیره می‌کنید.

با این حال، در حال تغییر در بخشی از API است . مهر زمانی که به تابع callback شما ارسال می‌شود، از زمانی که صفحه باز شده است، از یک مهر زمانی -مانند Date.now() با وضوح بالا به اندازه‌گیری ممیز شناور با وضوح بالا تغییر می‌کند. اگر از این مقدار استفاده می کنید، باید کد خود را بر اساس توضیحات زیر به روز کنید .

فقط برای واضح بودن، اینجا چیزی است که من در مورد آن صحبت می کنم:

// assuming requestAnimationFrame method has been normalized for all vendor prefixes..
requestAnimationFrame(function(timestamp){
    // the value of timestamp is changing
});

اگر از شیم متداول requestAnimFrame ارائه شده در اینجا استفاده می کنید، پس از مقدار مهر زمانی استفاده نمی کنید. شما از قلاب خارج شده اید. :)

چرا

چرا؟ خوب rAF به شما کمک می کند حداکثر سرعت 60 فریم در ثانیه را که ایده آل است، دریافت کنید و 60 فریم در ثانیه به 16.7 میلی ثانیه در هر فریم تبدیل می شود. اما اندازه‌گیری با میلی‌ثانیه‌های عدد صحیح به این معنی است که برای هر چیزی که می‌خواهیم مشاهده و هدف‌گیری کنیم، دقت 16/1 داریم.

مقایسه نمودار 16 میلی‌ثانیه در مقابل 16 میلی‌ثانیه صحیح.

همانطور که در بالا می بینید، نوار آبی نشان دهنده حداکثر زمانی است که شما باید قبل از رنگ آمیزی یک فریم جدید (با سرعت 60 فریم در ثانیه) تمام کارهای خود را انجام دهید. شما احتمالاً بیش از 16 کار را انجام می دهید، اما با اعداد صحیح میلی ثانیه فقط توانایی برنامه ریزی و اندازه گیری در آن افزایش های بسیار بزرگ را دارید. این به اندازه کافی خوب نیست.

تایمر با وضوح بالا با ارائه یک رقم بسیار دقیق تر این مشکل را حل می کند:

Date.now()         //  1337376068250
performance.now()  //  20303.427000007

تایمر با وضوح بالا در حال حاضر در Chrome با نام window.performance.webkitNow() موجود است، و این مقدار معمولاً برابر با مقدار آرگومان جدید ارسال شده به پاسخ تماس rAF است. هنگامی که مشخصات از طریق استانداردها بیشتر پیش رفت، متد پیشوند را حذف می کند و از طریق performance.now() در دسترس خواهد بود.

همچنین متوجه خواهید شد که دو مقدار بالا مرتبه های زیادی متفاوت هستند. performance.now() اندازه گیری میلی ثانیه ممیز شناور از زمانی است که آن صفحه خاص شروع به بارگذاری کرده است ( performance.navigationStart باید مشخص باشد).

در حال استفاده

مسئله کلیدی که برش داده می شود کتابخانه های انیمیشنی است که از این الگوی طراحی استفاده می کنند:

function MyAnimation(duration) {
    this.startTime = Date.now();
    this.duration = duration;
    requestAnimFrame(this.tick.bind(this));
}
MyAnimation.prototype.tick = function(time) {
    var now = Date.now();
    if (time > now) {
        this.dispatchEvent("ended");
        return;
    }
    ...
    requestAnimFrame(this.tick.bind(this));
}

ویرایش برای رفع این مشکل بسیار آسان است... startTime را افزایش دهید و now از window.performance.now() استفاده کنید.

this.startTime = window.performance.now ?
                    (performance.now() + performance.timing.navigationStart) :
                    Date.now();

این یک پیاده سازی نسبتا ساده است، از یک متد ( now() پیشوند استفاده نمی کند و همچنین پشتیبانی از Date.now() را فرض می کند که در IE8 نیست.

تشخیص ویژگی

اگر از الگوی بالا استفاده نمی‌کنید و فقط می‌خواهید مشخص کنید که چه نوع مقدار برگشتی را دریافت می‌کنید، می‌توانید از این تکنیک استفاده کنید:

requestAnimationFrame(function(timestamp){

    if (timestamp < 1e12){
        // .. high resolution timer
    } else {
        // integer milliseconds since unix epoch
    }

    // ...

بررسی if (timestamp < 1e12) یک آزمایش سریع است برای دیدن اینکه با چه اندازه عددی روبرو هستیم. از نظر فنی ممکن است مثبت کاذب باشد اما فقط در صورتی که یک صفحه وب به مدت 30 سال به طور مداوم باز باشد. اما ما نمی توانیم آزمایش کنیم که آیا این عدد یک عدد ممیز شناور است (به جای طبقه بندی شده به یک عدد صحیح). به اندازه کافی تایمر با وضوح بالا بخواهید و مطمئناً در برخی موارد مقادیر صحیح را دریافت خواهید کرد.

ما قصد داریم این تغییر را در Chrome 21 اعمال کنیم، بنابراین اگر قبلاً از این پارامتر پاسخ به تماس استفاده می‌کنید، حتماً کد خود را به‌روزرسانی کنید!