عرض وقت الاستجابة البطيء مع تلميح غير متزامن

Joe Medley
Joe Medley

الاختلافات في عرض قلم الشاشة

لطالما عانت تطبيقات الرسم المستندة إلى قلم الشاشة والمصمّمة للويب من مشاكل تتعلّق بوقت الاستجابة لأنّ صفحة الويب يجب أن تزامن تعديلات الرسومات مع DOM. في أي تطبيق للرسم، يمكن أن تؤدي أوقات الاستجابة التي تزيد عن 50 مللي ثانية إلى تداخل التنسيق بين اليد والعين لدى المستخدم، ما يجعل استخدام التطبيقات صعبًا.

يؤدي تلميح desynchronized لـ canvas.getContext() إلى استدعاء مسار تعليمات برمجية مختلف يتجاوز آلية تحديث DOM المعتادة. بدلاً من ذلك، يطلب التلميح من النظام الأساسي تخطّي أكبر قدر ممكن من عمليات الدمج، وفي بعض الحالات، يتم إرسال المخزن المؤقت الأساسي للوحة مباشرةً إلى معالج شاشة الشاشة. ويؤدي ذلك إلى إزالة وقت الاستجابة الذي قد ينتج عن استخدام قائمة الانتظار الخاصة بمركب العارض.

ما مدى جودة المُنتَج؟

عرض Sintel المتزامن

إذا أردت الاطّلاع على الرمز، انتقِل إلى الأسفل. للاطّلاع على كيفية استخدام هذه الميزة، تحتاج إلى جهاز مزوّد بشاشة تعمل باللمس، ويُفضَّل أن يكون مزوّدًا بقلم شاشة. (يمكنك أيضًا استخدام أصابعك). إذا كان لديك أحدهما، جرِّب الرسومات ثنائية الأبعاد أو webgl. بالنسبة إلى المستخدمين الآخرين، يمكنكم الاطّلاع على هذا العرض التجريبي الذي أعدّه المهندس ميغيل كاساس، وهو أحد المهندسين الذين نفّذوا هذه الميزة. افتح العرض التجريبي واضغط على زر التشغيل، ثم حرِّك شريط التمرير ذهابًا وإيابًا بشكل عشوائي وسريع.

يستخدم هذا المثال مقطعًا مدته دقيقة وإحدى وعشرون ثانية من الفيلم القصير Sintel الذي أنشأه "دوريان"، وهو مشروع مفتوح لإنشاء الأفلام باستخدام Blender. في هذا المثال، يتم تشغيل الفيلم في عنصر <video> يتم تحويل محتوياته في الوقت نفسه إلى عنصر <canvas>. يمكن للعديد من الأجهزة إجراء ذلك بدون حدوث تمزّق، إلا أنّ الأجهزة التي تستخدم ميزة عرض المخزن المؤقت الأمامي، مثل ChromeOS على سبيل المثال، قد تواجه تمزّقًا. (الفيلم رائع، ولكنه حزين. لم أستطع التركيز لمدة ساعة بعد رؤيته. نحذّرك من أنّه سيتم اتخاذ إجراءات بحقّك في حال تكرار المخالفة.)

استخدام التلميح

هناك فوائد أخرى لاستخدام وقت الاستجابة المنخفض غير إضافة desynchronized إلى canvas.getContext(). سأراجع المشاكل واحدة تلو الأخرى.

إنشاء اللوحة

في واجهة برمجة تطبيقات أخرى، سأناقش رصد الميزات أولاً. بالنسبة إلى 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!');
}

تجنُّب الوميض

هناك حالتان يمكن أن تتسبّب في حدوث وميض إذا لم يتمّ ترميز المحتوى بشكلٍ صحيح.

تُزيل بعض المتصفّحات، بما في ذلك Chrome، لوحات WebGL بين اللقطات. من المُحتمل أن يقرأ عنصر التحكّم في الشاشة المخزن المؤقت عندما يكون فارغًا، ما يؤدي إلى وميض الصورة المرسومة. لتجنُّب ذلك، عليك ضبط preserveDrawingBuffer على true.

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

يمكن أن يحدث الوميض أيضًا عند محو سياق الشاشة في رمز الرسم الخاص بك. إذا كان عليك محو المحتوى، ارسم على إطار تخزين مؤقت للصور خارج الشاشة ثم انسخ ذلك إلى الشاشة.

القنوات التجريبية

لا يزال بإمكانك إيقاف مزامنة عنصر لوحة شفافة تم ضبط قيمة "ألفا" فيه على "صحيح"، ولكن يجب ألا يتضمّن أي عناصر DOM أخرى فوقه.

يمكن أن يكون هناك حساب واحد فقط

لا يمكنك تغيير سمات السياق بعد أول طلب إلى canvas.getContext(). كان هذا صحيحًا دائمًا، ولكن تكرار هذه النقطة قد يجنبك بعض الإحباط في حال عدم معرفتك بذلك أو نسيانك له .

على سبيل المثال، لنفترض أنّني أحصل على سياق وحدّدت alpha على أنّها false، ثم أستدعي canvas.getContext() مرة ثانية في مكان لاحق من الرمز البرمجي مع ضبط alpha على 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 هما العنصر نفسه. لا يزال "ألفا" خطأ، ولا يتم أبدًا إنشاء سياق يكون فيه "ألفا" يساوي صحيحًا.

أنواع اللوحات المتوافقة

المعلمة الأولى التي تم تمريرها إلى getContext() هي contextType. إذا كنت على دراية بـ getContext()، لا شك أنّك تتساءل عما إذا كان هناك أي نوع آخر من أنواع السياق غير "2d" مسموح به. يعرض الجدول أدناه أنواع السياق التي تتيح استخدام desynchronized.

contextType عنصر نوع السياق

'2d'

CanvasRenderingContext2D

'webgl'

WebGLRenderingContext

'webgl2'

WebGL2RenderingContext

الخاتمة

إذا أردت الاطّلاع على المزيد من هذه الأنواع من المحتوى، يمكنك الاطّلاع على العيّنات. بالإضافة إلى مثال الفيديو الذي سبق أن وصفناه، تتوفّر أمثلة تعرض سياقَي ‎2d و‎webgl.