การแสดงผลเวลาในการตอบสนองต่ำพร้อมคำแนะนำแบบไม่พร้อมกัน

Joe Medley
Joe Medley

ความแตกต่างของการแสดงผลสไตลัส

แอปพลิเคชันวาดภาพที่ใช้ปากกาสไตลัสซึ่งสร้างขึ้นสำหรับเว็บประสบปัญหาเกี่ยวกับเวลาในการตอบสนองมาอย่างยาวนาน เนื่องจากหน้าเว็บต้องซิงค์การอัปเดตกราฟิกกับ DOM ในแอปพลิเคชันวาดภาพใดๆ เวลาในการตอบสนองนานกว่า 50 มิลลิวินาทีอาจรบกวนการทำงานของมือและตาของผู้ใช้ ทำให้แอปพลิเคชันใช้งานยาก

คำแนะนำ desynchronized สำหรับ canvas.getContext() จะเรียกใช้เส้นทางโค้ดอื่นที่ข้ามกลไกการอัปเดต DOM ตามปกติ แต่จะบอกให้ระบบพื้นฐานข้ามการคอมโพสได้มากเท่าที่จะทำได้ และในบางกรณี ระบบจะส่งบัฟเฟอร์พื้นฐานของ Canvas ไปยังตัวควบคุมการแสดงผลของหน้าจอโดยตรง วิธีนี้จะช่วยขจัดเวลาในการตอบสนองที่อาจเกิดขึ้นจากการใช้คิวคอมโพสิตโปรแกรมแสดงผล

ผลิตภัณฑ์ดีแค่ไหน

การแสดงผล Sintel พร้อมกัน

หากต้องการดูรหัส ให้เลื่อนไปข้างหน้า หากต้องการดูวิธีการใช้งาน คุณต้องมีอุปกรณ์ที่มีหน้าจอสัมผัส และควรมีปากกาสไตลัส (ใช้นิ้วได้เช่นกัน) หากมี ให้ลองใช้ตัวอย่าง 2d หรือ webgl ส่วนผู้ใช้งานคนอื่นๆ โปรดดูการสาธิตโดย Miguel Casas ซึ่งเป็นวิศวกรที่ติดตั้งใช้งานฟีเจอร์นี้ เปิดเดโม กดเล่น แล้วเลื่อนแถบเลื่อนไปมาแบบสุ่มและรวดเร็ว

ตัวอย่างนี้ใช้คลิปความยาว 1 นาที 21 วินาทีจากภาพยนตร์สั้น Sintel โดย Durian ซึ่งเป็นโปรเจ็กต์ภาพยนตร์โอเพนซอร์สของ Blender ในตัวอย่างนี้ ภาพยนตร์จะเล่นในองค์ประกอบ <video> ซึ่งเนื้อหาจะแสดงผลในองค์ประกอบ <canvas> พร้อมกัน อุปกรณ์จํานวนมากทําเช่นนี้ได้โดยไม่ฉีกขาด แต่อุปกรณ์ที่มีการเรนเดอร์บัฟเฟอร์ด้านหน้า เช่น ChromeOS อาจฉีกขาด (ภาพยนตร์เรื่องนี้ยอดเยี่ยมแต่ก็น่าเศร้า ฉันทำอะไรไม่ได้เลยเป็นเวลา 1 ชั่วโมงหลังจากเห็น โปรดรับทราบคำเตือนนี้)

การใช้คำแนะนำ

การใช้เวลาในการตอบสนองต่ำนั้นมีประโยชน์มากกว่าการเพิ่ม 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!');
}

หลีกเลี่ยงการกะพริบ

มี 2 กรณีที่อาจทำให้เกิดภาพกะพริบหากคุณเขียนโค้ดไม่ถูกต้อง

บางเบราว์เซอร์รวมถึง Chrome จะล้างแคนวาส WebGL ระหว่างเฟรม ตัวควบคุมจอแสดงผลอาจอ่านบัฟเฟอร์ขณะที่ว่างเปล่า ซึ่งทำให้รูปภาพที่วาดกระพริบ วิธีหลีกเลี่ยงปัญหานี้คือการตั้งค่า preserveDrawingBuffer เป็น true

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

นอกจากนี้ การสั่นไหวยังอาจเกิดขึ้นเมื่อคุณล้างบริบทหน้าจอในโค้ดการวาดของคุณเอง หากต้องล้าง ให้วาดลงในเฟรมบัฟเฟอร์นอกหน้าจอ แล้วคัดลอกไปยังหน้าจอ

ช่องอัลฟ่า

องค์ประกอบ Canvas แบบโปร่งแสงซึ่งตั้งค่าอัลฟ่าเป็น "จริง" จะยังคงยกเลิกการซิงค์ได้ แต่ต้องไม่มีองค์ประกอบ 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 ไม่ใช่วัตถุเดียวกัน Alpha จะยังคงเป็นเท็จและจะไม่มีการสร้างบริบทที่มี alpha เท่ากับจริง

ประเภทแคนวาสที่รองรับ

พารามิเตอร์แรกที่ส่งไปยัง getContext() คือ contextType หากคุ้นเคยกับ getContext() อยู่แล้ว คุณอาจสงสัยว่าระบบรองรับบริบทประเภทอื่นนอกเหนือจาก "2 มิติ" หรือไม่ ตารางด้านล่างแสดงประเภทบริบทที่รองรับ desynchronized

contextType ออบเจ็กต์ประเภทบริบท

'2d'

CanvasRenderingContext2D

'webgl'

WebGLRenderingContext

'webgl2'

WebGL2RenderingContext

บทสรุป

หากต้องการดูตัวอย่างเพิ่มเติม ให้ดูที่แท็บ "ลองฟัง" นอกจากตัวอย่างวิดีโอที่อธิบายไปแล้ว ยังมีตัวอย่างที่แสดงทั้งบริบท '2d' และ 'webgl'