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

Joe Medley
Joe Medley

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

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

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

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

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

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

ตัวอย่างนี้ใช้คลิปความยาว 1 นาที 21 วินาทีจากภาพยนตร์สั้นเรื่อง Sintel โดย Durian ซึ่งเป็นโปรเจ็กต์ภาพยนตร์เปิดเรื่อง ในตัวอย่างนี้ ภาพยนตร์จะเล่นในองค์ประกอบ <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 อื่นๆ อยู่เหนือองค์ประกอบดังกล่าว

มีได้ 1 ประเภทเท่านั้น

คุณจะเปลี่ยนแอตทริบิวต์บริบทหลังจากเรียกไปยัง canvas.getContext() ครั้งแรกไม่ได้ ความรู้สึกเช่นนี้มักจะเกิดขึ้นเสมอ แต่การกล่าวซ้ำๆ อาจช่วยให้คุณรู้สึกหงุดหงิดได้หากคุณไม่รู้ตัวหรือลืมไป

ตัวอย่างเช่น สมมติว่าผมได้รับบริบทและระบุอัลฟ่าเป็น "เท็จ" จากนั้นผมเรียก canvas.getContext() เป็นครั้งที่ 2 ในโค้ดของผมด้วยการตั้งค่าอัลฟ่าเป็น "จริง" ดังที่แสดงด้านล่าง

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 ยังคงเป็นเท็จอยู่ และจะไม่มีการสร้างบริบทที่มีอัลฟ่าเท่ากับ "จริง"

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

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

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

'2d'

CanvasRenderingContext2D

'webgl'

WebGLRenderingContext

'webgl2'

WebGL2RenderingContext

บทสรุป

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