رندر با تأخیر کم با اشاره غیرهمگام

جو مدلی
Joe Medley

تفاوت در رندر قلم

برنامه‌های طراحی مبتنی بر قلم ساخته شده برای وب مدت‌هاست که از مشکلات تأخیر رنج می‌برند، زیرا یک صفحه وب باید به‌روزرسانی‌های گرافیکی را با DOM همگام‌سازی کند. در هر برنامه طراحی، تأخیر بیش از 50 میلی ثانیه می تواند در هماهنگی دست و چشم کاربر اختلال ایجاد کند و استفاده از برنامه ها را دشوار کند.

اشاره desynchronized برای canvas.getContext() یک مسیر کد متفاوت را فراخوانی می‌کند که مکانیسم معمول به‌روزرسانی DOM را دور می‌زند. در عوض، راهنمایی به سیستم زیربنایی می‌گوید که تا جایی که می‌تواند از ترکیب کردن صرفنظر کند و در برخی موارد، بافر زیربنایی بوم مستقیماً به کنترل‌کننده نمایش صفحه نمایش ارسال می‌شود. این تأخیر را که با استفاده از صف سازنده رندر ایجاد می شود، از بین می برد.

چقدر خوبه

رندر همزمان سینتل

اگر می خواهید به کد برسید، به جلو بروید. برای اینکه آن را در عمل ببینید، به دستگاهی با صفحه نمایش لمسی و ترجیحاً یک قلم نیاز دارید. (انگشتان هم کار می کند.) اگر یکی دارید، نمونه های 2d یا webgl را امتحان کنید. برای بقیه، این نسخه ی نمایشی توسط میگل کاساس ، یکی از مهندسانی که این ویژگی را اجرا کرده است، بررسی کنید. دمو را باز کنید، play را فشار دهید، سپس نوار لغزنده را به صورت تصادفی و سریع به جلو و عقب ببرید.

این مثال از یک کلیپ یک دقیقه ای و بیست و یک ثانیه ای از فیلم کوتاه Sintel ساخته دوریان، پروژه فیلم باز Blender استفاده می کند. در این مثال، فیلم در یک عنصر <video> پخش می شود که محتوای آن به طور همزمان به عنصر <canvas> ارائه می شود. بسیاری از دستگاه‌ها می‌توانند این کار را بدون پاره شدن انجام دهند، اگرچه دستگاه‌هایی با رندر بافر جلویی مانند ChromeOS ممکن است دچار پارگی شوند. (فیلم عالیه ولی دلخراش. بعد از دیدنش تا یک ساعت بی فایده بودم. خودتون رو اخطار در نظر بگیرید.)

با استفاده از اشاره

استفاده از تأخیر کم بیشتر از افزودن desynchronized به canvas.getContext() است. من مسائل را یکی یکی مرور می کنم.

بوم را ایجاد کنید

در یک API دیگر، ابتدا در مورد تشخیص ویژگی بحث می کنم. برای اشاره desynchronized ابتدا باید بوم را ایجاد کنید. canvas.getContext() را فراخوانی کنید و راهنمایی desynchronized جدید را با مقدار true ارسال کنید.

const canvas = document.querySelector('myCanvas');
const ctx = canvas.getContext('2d', {
  desynchronized: true,
  // Other options. See below.
});

تشخیص ویژگی

سپس getContextAttributes() را فراخوانی کنید. اگر شیء ویژگی های برگردانده شده دارای یک ویژگی desynchronized است، آن را آزمایش کنید.

if (ctx.getContextAttributes().desynchronized) {
  console.log('Low latency canvas supported. Yay!');
} else {
  console.log('Low latency canvas not supported. Boo!');
}

اجتناب از سوسو زدن

دو مورد وجود دارد که اگر به درستی کدنویسی نکنید، می توانید سوسو زدن ایجاد کنید.

برخی از مرورگرها از جمله کروم بوم های WebGL را بین فریم ها پاک می کنند. این امکان وجود دارد که کنترلر صفحه نمایش بافر را در حالی که خالی است بخواند و باعث سوسو زدن تصویر کشیده شود. برای جلوگیری از این امر باید preserveDrawingBuffer را روی true تنظیم کنید.

const canvas = document.querySelector('myCanvas');
const ctx = canvas.getContext('webgl', {
  desynchronized: true,
  preserveDrawingBuffer: true
});

هنگامی که زمینه صفحه را در کد طراحی خود پاک می کنید، سوسو زدن نیز می تواند رخ دهد. اگر باید پاک کنید، به یک فریم بافر خارج از صفحه بکشید و سپس آن را روی صفحه کپی کنید.

کانال های آلفا

یک عنصر بوم نیمه شفاف، عنصری که در آن آلفا روی true تنظیم شده است، همچنان می‌تواند همگام‌سازی شود، اما نباید هیچ عنصر DOM دیگری در بالای خود داشته باشد.

تنها یکی می تواند باشد

شما نمی توانید ویژگی های متن را پس از اولین فراخوانی به canvas.getContext() تغییر دهید. این همیشه درست بوده است، اما تکرار آن ممکن است شما را از ناراحتی نجات دهد، اگر بی‌خبر باشید یا فراموش کرده باشید.

برای مثال، فرض کنید که من یک متن دریافت می‌کنم و آلفا را به‌عنوان false مشخص می‌کنم، سپس در جایی بعد در کدم، برای بار دوم canvas.getContext() را با آلفا روی true مانند شکل زیر فراخوانی می‌کنم.

const canvas = document.querySelector('myCanvas');
const ctx1 = canvas.getContext('2d', {
  alpha: false,
  desynchronized: true,
});

//Some time later, in another corner of code.
const ctx2 = canvas.getContext('2d', {
  alpha: true,
  desynchronized: true,
});

واضح نیست که ctx1 و ctx2 یک شی هستند. آلفا هنوز نادرست است و زمینه ای با آلفا برابر با true هرگز ایجاد نمی شود.

انواع بوم پشتیبانی شده

اولین پارامتری که به getContext() داده می شود contextType است. اگر قبلاً با getContext() آشنا هستید، بدون شک نمی‌دانید که آیا چیز دیگری غیر از انواع زمینه «2d» پشتیبانی می‌شود. جدول زیر انواع زمینه‌ای را نشان می‌دهد که desynchronized پشتیبانی می‌کنند.

contextType شی نوع زمینه

'2d'

CanvasRenderingContext2D

'webgl'

WebGLRenderingContext

'webgl2'

WebGL2RenderingContext

نتیجه

اگر می خواهید بیشتر از این را ببینید، نمونه ها را بررسی کنید. علاوه بر مثال ویدیویی که قبلاً توضیح داده شد، نمونه‌هایی وجود دارد که هر دو زمینه «2d» و «webgl» را نشان می‌دهند.