บทนำ
แคนวาส HTML5 ซึ่งเริ่มต้นจากการทดลองของ Apple เป็นมาตรฐานที่รองรับมากที่สุดสำหรับกราฟิกโหมดทันที 2 มิติบนเว็บ ปัจจุบันนักพัฒนาซอฟต์แวร์จำนวนมากใช้ประโยชน์จาก โครงการมัลติมีเดีย การแสดงภาพ และเกม อย่างไรก็ตาม เมื่อแอปพลิเคชันที่เราสร้างมีความซับซ้อนมากขึ้น นักพัฒนาแอปอาจพบปัญหาด้านประสิทธิภาพโดยไม่ตั้งใจ มีแนวคิดที่ไม่เกี่ยวข้องกันมากมายเกี่ยวกับการเพิ่มประสิทธิภาพแคนวาส บทความนี้มีจุดประสงค์เพื่อรวบรวมข้อมูลบางส่วนนี้ให้เป็นแหล่งข้อมูลที่นักพัฒนาแอปเข้าใจได้ง่ายขึ้น บทความนี้ประกอบด้วยการเพิ่มประสิทธิภาพขั้นพื้นฐานที่มีผลกับสภาพแวดล้อมคอมพิวเตอร์กราฟิกทั้งหมด ตลอดจนเทคนิคเฉพาะสำหรับ Canvas ซึ่งอาจมีการเปลี่ยนแปลงเมื่อการติดตั้งใช้งาน Canvas ได้รับการปรับปรุงให้ดีขึ้น โดยเฉพาะอย่างยิ่งเมื่อผู้ให้บริการเบราว์เซอร์ใช้การเร่ง GPU ของ Canvas เทคนิคด้านประสิทธิภาพบางอย่างที่ระบุไว้อาจมีผลน้อยลง เราจะระบุข้อมูลนี้ไว้ตามความเหมาะสม โปรดทราบว่าบทความนี้ไม่ได้กล่าวถึงการใช้งาน Canvas ของ HTML5 โปรดอ่านบทความที่เกี่ยวข้องกับ Canvas เหล่านี้ใน HTML5Rocks, บทนี้ในเว็บไซต์ Dive into HTML5 หรือบทแนะนำ MDN Canvas
การทดสอบประสิทธิภาพ
ในการจัดการกับโลกแห่ง Canvas ของ HTML5 ที่เปลี่ยนแปลงอย่างรวดเร็ว การทดสอบ JSPerf (jsperf.com) จะตรวจสอบว่าการเพิ่มประสิทธิภาพที่เสนอทั้งหมดยังคงทำงานอยู่ JSPerf เป็นเว็บแอปพลิเคชันที่ช่วยให้นักพัฒนาซอฟต์แวร์เขียนการทดสอบประสิทธิภาพ JavaScript ได้ การทดสอบแต่ละรายการจะมุ่งเน้นที่ผลลัพธ์ที่คุณพยายามจะบรรลุ (เช่น การล้างแคนวาส) และมีหลายวิธีที่จะให้ผลลัพธ์เดียวกัน JSPerf จะเรียกใช้แนวทางแต่ละวิธีให้มากที่สุดเท่าที่จะเป็นไปได้ในช่วงเวลาสั้นๆ และแสดงจํานวนการทําซ้ำต่อวินาทีที่มีนัยสำคัญทางสถิติ คะแนนสูงย่อมดีกว่าเสมอ ผู้เข้าชมหน้าการทดสอบประสิทธิภาพของ JSPerf สามารถเรียกใช้การทดสอบในเบราว์เซอร์ของตนเอง และอนุญาตให้ JSPerf จัดเก็บผลการทดสอบที่ปรับมาตรฐานแล้วใน Browserscope (browserscope.org) เนื่องจากเทคนิคการเพิ่มประสิทธิภาพในบทความนี้ได้รับการสนับสนุนโดยผลลัพธ์ JSPerf คุณจึงกลับไปดูข้อมูลล่าสุดเกี่ยวกับเทคนิคนั้นว่ายังคงใช้งานได้อยู่หรือไม่ เราได้เขียนแอปพลิเคชันตัวช่วยเล็กๆ ขึ้นมาเพื่อแสดงผลลัพธ์เหล่านี้เป็นกราฟ ซึ่งฝังอยู่ในบทความนี้
ผลลัพธ์ด้านประสิทธิภาพทั้งหมดในบทความนี้จะอิงตามเวอร์ชันเบราว์เซอร์ ซึ่งกลายเป็นข้อจำกัดเนื่องจากเราไม่ทราบว่าเบราว์เซอร์ทำงานบนระบบปฏิบัติการใด หรือที่สำคัญกว่านั้นคือ HTML5 canvas ได้รับการเร่งด้วยฮาร์ดแวร์หรือไม่เมื่อทำการทดสอบประสิทธิภาพ คุณสามารถดูว่าแคนวาส HTML5 ของ Chrome มีการเร่งด้วยฮาร์ดแวร์หรือไม่โดยไปที่ about:gpu
ในแถบที่อยู่
แสดงผลก่อนไปยังแคนวาสนอกหน้าจอ
หากคุณวาดรูปเรขาคณิตพื้นฐานที่คล้ายกันบนหน้าจอซ้ำหลายเฟรม ซึ่งมักเกิดขึ้นเมื่อเขียนเกม คุณจะเพิ่มประสิทธิภาพได้อย่างมากด้วยการเรนเดอร์ฉากส่วนใหญ่ล่วงหน้า การแสดงผลล่วงหน้าหมายถึงการใช้แคนวาสนอกหน้าจอ (หรือแคนวาส) แยกต่างหากในการแสดงผลรูปภาพชั่วคราว แล้วแสดงผลแคนวาสนอกหน้าจอกลับคืนมาเป็นภาพที่มองเห็นได้ ตัวอย่างเช่น สมมติว่าคุณวาดภาพมาริโอวิ่งซ้ำที่ 60 เฟรมต่อวินาที คุณอาจวาดหมวก หนวด และตัว "M" อีกครั้งในแต่ละเฟรม หรือแสดงผลล่วงหน้า Mario ก่อนที่จะเรียกใช้ภาพเคลื่อนไหว ไม่มีการแสดงผลล่วงหน้า
// canvas, context are defined
function render() {
drawMario(context);
requestAnimationFrame(render);
}
การแสดงผลล่วงหน้า:
var m_canvas = document.createElement('canvas');
m_canvas.width = 64;
m_canvas.height = 64;
var m_context = m_canvas.getContext('2d');
drawMario(m_context);
function render() {
context.drawImage(m_canvas, 0, 0);
requestAnimationFrame(render);
}
โปรดสังเกตการใช้ requestAnimationFrame
ซึ่งจะอธิบายอย่างละเอียดในส่วนถัดไป
เทคนิคนี้จะมีประสิทธิภาพเป็นพิเศษเมื่อการดำเนินการแสดงผล (drawMario
ในตัวอย่างด้านบน) มีค่าใช้จ่ายสูง ตัวอย่างที่ดีของกรณีนี้คือการแสดงผลข้อความ ซึ่งเป็นการดำเนินการที่สิ้นเปลืองทรัพยากรมาก
อย่างไรก็ตาม เฟรมทดสอบ "ภาพพร่ามัวที่แสดงผลล่วงหน้า" มีประสิทธิภาพต่ำ เมื่อแสดงผลก่อนผ่านโปรแกรมประมวลผลภาพ คุณต้องตรวจสอบว่าภาพพิมพ์แคนวาสชั่วคราวพอดีกับรูปภาพที่คุณวาด มิเช่นนั้นประสิทธิภาพที่เพิ่มขึ้นจากการแสดงผลนอกหน้าจอจะลดลงเนื่องจากการคัดลอกภาพพิมพ์แคนวาสขนาดใหญ่ไปยังอีกภาพหนึ่ง (ซึ่งจะแตกต่างกันไปตามขนาดเป้าหมายต้นทาง) ภาพแคนวาสที่พอดีในการทดสอบด้านบนมีขนาดเล็กกว่าเท่านั้น
can2.width = 100;
can2.height = 40;
เมื่อเทียบกับการใส่แบบหลวมๆ ซึ่งให้ประสิทธิภาพต่ำกว่า
can3.width = 300;
can3.height = 100;
รวมการเรียกใช้ Canvas หลายรายการเข้าด้วยกัน
เนื่องจากการวาดเป็นการดำเนินการที่มีค่าใช้จ่ายสูง การโหลดเครื่องสถานะการวาดด้วยชุดคำสั่งที่ยาวๆ แล้วให้ทิ้งชุดคำสั่งทั้งหมดลงในบัฟเฟอร์วิดีโอจึงมีประสิทธิภาพมากกว่า
ตัวอย่างเช่น เมื่อวาดเส้นหลายเส้น การสร้างเส้นทางเดียวที่มีเส้นทั้งหมดอยู่ในนั้นจะมีประสิทธิภาพมากกว่า และวาดด้วยการวาดเส้นเดียว กล่าวคือ ให้ทำดังนี้แทนการวาดเส้นแยกกัน
for (var i = 0; i < points.length - 1; i++) {
var p1 = points[i];
var p2 = points[i+1];
context.beginPath();
context.moveTo(p1.x, p1.y);
context.lineTo(p2.x, p2.y);
context.stroke();
}
เราได้รับประสิทธิภาพที่ดีขึ้นจากการวาดเส้นประกอบเดี่ยว
context.beginPath();
for (var i = 0; i < points.length - 1; i++) {
var p1 = points[i];
var p2 = points[i+1];
context.moveTo(p1.x, p1.y);
context.lineTo(p2.x, p2.y);
}
context.stroke();
หลักการนี้ยังใช้กับแคนวาส HTML5 ด้วย เช่น เมื่อวาดเส้นทางที่ซับซ้อน คุณควรใส่จุดทั้งหมดลงในเส้นทางแทนที่จะแสดงผลแต่ละส่วนของเส้นทางแยกกัน (jsperf)
อย่างไรก็ตาม โปรดทราบว่าใน Canvas มีข้อยกเว้นที่สำคัญสำหรับกฎนี้ นั่นคือ หากค่าพื้นฐานที่เกี่ยวข้องกับการวาดวัตถุที่ต้องการมีกรอบล้อมรอบขนาดเล็ก (เช่น เส้นแนวนอนและแนวตั้ง) การแสดงผลแยกกันอาจมีประสิทธิภาพมากกว่า (jsperf)
หลีกเลี่ยงการเปลี่ยนแปลงสถานะ Canvas ที่ไม่จำเป็น
องค์ประกอบ Canvas ของ HTML5 ทำงานบนสถานะแมชชีนที่ติดตามข้อมูลต่างๆ เช่น สไตล์การเติมและจังหวะ รวมถึงจุดก่อนหน้าที่ประกอบกันเป็นเส้นทางปัจจุบัน เมื่อพยายามเพิ่มประสิทธิภาพของกราฟิก คุณอาจห้ามความสนใจไปที่การแสดงภาพกราฟิกเพียงอย่างเดียว อย่างไรก็ตาม การจัดการเครื่องสถานะก็สร้างค่าใช้จ่ายในการดำเนินการเพิ่มได้ เช่น หากใช้สีพื้นหลายสีเพื่อแสดงผลฉาก การแสดงผลตามสีจะประหยัดกว่าการแสดงผลตามตำแหน่งบนผืนผ้าใบ หากต้องการแสดงผลลายทางเล็ก คุณอาจต้องแสดงผลแถบ เปลี่ยนสี แสดงผลแถบถัดไป ฯลฯ
for (var i = 0; i < STRIPES; i++) {
context.fillStyle = (i % 2 ? COLOR1 : COLOR2);
context.fillRect(i * GAP, 0, GAP, 480);
}
หรือแสดงผลแถบเลขคี่ทั้งหมดก่อนแล้วตามด้วยแถบเลขคู่ทั้งหมด
context.fillStyle = COLOR1;
for (var i = 0; i < STRIPES/2; i++) {
context.fillRect((i*2) * GAP, 0, GAP, 480);
}
context.fillStyle = COLOR2;
for (var i = 0; i < STRIPES/2; i++) {
context.fillRect((i*2+1) * GAP, 0, GAP, 480);
}
ตามที่คาดไว้ วิธีการแบบอินเตอร์เลซจะช้ากว่าเนื่องจากการเปลี่ยนเครื่องสถานะมีค่าใช้จ่ายสูง
แสดงความแตกต่างของหน้าจอเท่านั้น ไม่ใช่สถานะใหม่ทั้งหมด
ตามที่คาดไว้ การเรนเดอร์น้อยลงบนหน้าจอจะประหยัดกว่าการเรนเดอร์มากขึ้น หากมีเพียงความแตกต่างที่เพิ่มขึ้นระหว่างการวาดใหม่ คุณก็สามารถเพิ่มประสิทธิภาพได้อย่างมากด้วยการวาดความแตกต่าง กล่าวคือ แทนที่จะล้างทั้งหน้าจอก่อนวาด ให้ทำดังนี้
context.fillRect(0, 0, canvas.width, canvas.height);
ติดตามกรอบขอบเขตที่วาดไว้ แล้วล้างเฉพาะกรอบขอบเขตนั้น
context.fillRect(last.x, last.y, last.width, last.height);
หากคุ้นเคยกับคอมพิวเตอร์กราฟิก คุณอาจรู้จักเทคนิคนี้ในชื่อ "วาดภาพขอบเขตใหม่" ซึ่งระบบจะบันทึกกล่องขอบเขตที่ผ่านการจัดการแสดงผลก่อนหน้านี้ จากนั้นล้างออกในการแสดงผลแต่ละครั้ง เทคนิคนี้ยังสามารถใช้ได้กับบริบทการแสดงผลแบบพิกเซลด้วย ดังที่แสดงในการพูดเกี่ยวกับโปรแกรมจำลองของ Nintendo
ใช้ผืนผ้าใบหลายเลเยอร์สำหรับฉากที่ซับซ้อน
ดังที่กล่าวไปก่อนหน้านี้ การวาดภาพขนาดใหญ่มีค่าใช้จ่ายสูงและควรหลีกเลี่ยงหากเป็นไปได้ นอกจากการใช้ผืนผ้าใบอื่นสำหรับการเรนเดอร์นอกหน้าจอตามที่แสดงในส่วนการเรนเดอร์ล่วงหน้าแล้ว เรายังใช้ผืนผ้าใบที่วางซ้อนกันได้ด้วย ด้วยการใช้ความโปร่งใสในผืนผ้าใบพื้นหน้า เราสามารถใช้ GPU ในการประกอบอัลฟ่าเข้าด้วยกันในเวลาแสดงผล คุณอาจตั้งค่าดังนี้โดยมีภาพพิมพ์แคนวาส 2 ภาพที่วางซ้อนกัน
<canvas id="bg" width="640" height="480" style="position: absolute; z-index: 0">
</canvas>
<canvas id="fg" width="640" height="480" style="position: absolute; z-index: 1">
</canvas>
ข้อดีของการใช้ภาพพิมพ์แคนวาส 2 ภาพนี้ก็คือเมื่อเราวาดหรือล้างภาพพิมพ์แคนวาสที่อยู่เบื้องหน้า เราจะไม่แก้ไขพื้นหลัง หากเกมหรือแอปมัลติมีเดียของคุณแยกออกเป็นพื้นหน้าและพื้นหลังได้ ให้ลองแสดงผลบนผืนผ้าใบแยกกันเพื่อเพิ่มประสิทธิภาพอย่างเห็นได้ชัด
คุณมักจะใช้ประโยชน์จากการรับรู้ที่ไม่สมบูรณ์ของมนุษย์และแสดงผลเบื้องหลังเพียงครั้งเดียวหรือช้ากว่าเบื้องหน้า (ซึ่งมักจะดึงดูดความสนใจของผู้ใช้ส่วนใหญ่) เช่น คุณอาจเรนเดอร์พื้นหน้าทุกครั้งที่เรนเดอร์ แต่เรนเดอร์พื้นหลังทุกๆ N เฟรมเท่านั้น และโปรดทราบว่าวิธีนี้เหมาะกับแคนวาสแบบผสมจำนวนเท่าใดก็ได้ หากแอปพลิเคชันทำงานกับโครงสร้างแบบนี้ได้ดีกว่า
หลีกเลี่ยงการใช้ shadowBlur
เช่นเดียวกับสภาพแวดล้อมกราฟิกอื่นๆ อีกมากมาย แคนวาส HTML5 ช่วยให้นักพัฒนาซอฟต์แวร์เบลอองค์ประกอบพื้นฐานได้ แต่การดำเนินการนี้อาจใช้ทรัพยากรมาก
context.shadowOffsetX = 5;
context.shadowOffsetY = 5;
context.shadowBlur = 4;
context.shadowColor = 'rgba(255, 0, 0, 0.5)';
context.fillRect(20, 20, 150, 100);
ทำความรู้จักวิธีต่างๆ ในการล้างภาพพิมพ์แคนวาส
เนื่องจาก Canvas ของ HTML5 เป็นรูปแบบการวาดโหมดทันที จึงต้องมีการวาดฉากใหม่อย่างชัดเจนในแต่ละเฟรม ด้วยเหตุนี้ การล้าง Canvas จึงเป็นการดำเนินการที่สำคัญโดยพื้นฐานสำหรับแอปและเกม Canvas แบบ HTML5
ตามที่ระบุไว้ในส่วนหลีกเลี่ยงการเปลี่ยนแปลงสถานะ Canvas นั้น การล้าง Canvas ทั้งหมดมักเป็นสิ่งที่ไม่ต้องการ แต่หากคุณต้องทํา ก็มี 2 ตัวเลือก ได้แก่ การเรียกใช้ context.clearRect(0, 0, width, height)
หรือการใช้แฮ็กเฉพาะ Canvas เพื่อทำดังนี้
canvas.width = canvas.width
; ณ เวลาที่เขียน โดยทั่วไป clearRect
จะมีประสิทธิภาพดีกว่าเวอร์ชันที่รีเซ็ตความกว้าง แต่บางกรณีการใช้แฮ็กการรีเซ็ต canvas.width
จะเร็วกว่ามากใน Chrome 14
โปรดใช้เคล็ดลับนี้อย่างระมัดระวัง เนื่องจากขึ้นอยู่กับการใช้งาน Canvas พื้นฐานเป็นอย่างมากและอาจมีการเปลี่ยนแปลงได้ ดูข้อมูลเพิ่มเติมได้ที่บทความของ Simon Sarris เกี่ยวกับการล้างภาพพิมพ์แคนวาส
หลีกเลี่ยงพิกัดทศนิยม
แคนวาส HTML5 รองรับการแสดงผลระดับพิกเซลย่อย และปิดการแสดงผลระดับพิกเซลย่อยไม่ได้ หากคุณวาดด้วยพิกัดที่ไม่ใช่จำนวนเต็ม แคนวาสจะใช้การลบรอยหยักโดยอัตโนมัติเพื่อพยายามทำให้เส้นเรียบ เอฟเฟกต์ภาพนี้นำมาจากบทความเกี่ยวกับประสิทธิภาพของ Canvas ระดับพิกเซลย่อยโดย Seb Lee-Delisle
หากสไปรท์ที่ผ่านการปรับเรียบไม่ใช่เอฟเฟ็กต์ที่คุณต้องการ การแปลงพิกัดเป็นจำนวนเต็มโดยใช้ Math.floor
หรือ Math.round
(jsperf) จะเร็วกว่ามาก
หากต้องการแปลงพิกัดทศนิยมเป็นจำนวนเต็ม คุณสามารถใช้เทคนิคที่ชาญฉลาดหลายวิธี ซึ่งวิธีที่มีประสิทธิภาพมากที่สุดคือการบวกครึ่งหนึ่งกับตัวเลขเป้าหมาย แล้วทำการดำเนินการแบบบิตต่อผลลัพธ์เพื่อนำส่วนที่เป็นทศนิยมออก
// With a bitwise or.
rounded = (0.5 + somenum) | 0;
// A double bitwise not.
rounded = ~~ (0.5 + somenum);
// Finally, a left bitwise shift.
rounded = (0.5 + somenum) << 0;
ดูรายละเอียดประสิทธิภาพทั้งหมดได้ที่นี่ (jsperf)
โปรดทราบว่าการเพิ่มประสิทธิภาพประเภทนี้ไม่มีความสำคัญอีกต่อไปเมื่อการใช้งาน Canvas มีการเร่งโดยใช้ GPU ซึ่งจะทำให้แสดงผลพิกัดที่ไม่ใช่จำนวนเต็มได้อย่างรวดเร็ว
เพิ่มประสิทธิภาพภาพเคลื่อนไหวด้วย requestAnimationFrame
requestAnimationFrame
API ซึ่งเป็น API ที่ค่อนข้างใหม่เป็นวิธีที่แนะนําในการใช้งานแอปพลิเคชันอินเทอร์แอกทีฟในเบราว์เซอร์ คุณควรขอให้เบราว์เซอร์เรียกใช้กิจวัตรการแสดงผลอย่างสุภาพและรับการเรียกใช้เมื่อเบราว์เซอร์พร้อมใช้งานแทนที่จะสั่งให้เบราว์เซอร์แสดงผลที่อัตราทิกคงที่ ผลพลอยได้ที่น่าสนใจคือ หากหน้าเว็บไม่ได้อยู่เบื้องหน้า เบราว์เซอร์จะฉลาดพอที่จะไม่แสดงผล
requestAnimationFrame
การเรียกกลับมีเป้าหมายที่อัตราเฟรม 60 FPS แต่ไม่ได้รับประกัน คุณจึงต้องติดตามระยะเวลาที่ผ่านไปนับตั้งแต่การเรนเดอร์ครั้งล่าสุด ซึ่งอาจมีลักษณะดังนี้
var x = 100;
var y = 100;
var lastRender = Date.now();
function render() {
var delta = Date.now() - lastRender;
x += delta;
y += delta;
context.fillRect(x, y, W, H);
requestAnimationFrame(render);
}
render();
โปรดทราบว่าการใช้ requestAnimationFrame
นี้มีผลกับ Canvas รวมถึงเทคโนโลยีการแสดงผลอื่นๆ เช่น WebGL
ในขณะที่เขียน API นี้มีให้บริการเฉพาะใน Chrome, Safari และ Firefox เท่านั้น คุณจึงควรใช้ shim นี้
การใช้งานแคนวาสบนอุปกรณ์เคลื่อนที่ส่วนใหญ่ทำงานช้า
มาพูดถึงอุปกรณ์เคลื่อนที่กัน ขออภัย ณ เวลาที่เขียน มีเพียง iOS 5.0 เบต้าที่ใช้ Safari 5.1 เท่านั้นที่มีการใช้งาน Canvas บนอุปกรณ์เคลื่อนที่ที่เร่งด้วย GPU หากไม่มีการเร่งด้วย GPU โดยทั่วไปเบราว์เซอร์ในอุปกรณ์เคลื่อนที่จะมี CPU ที่ไม่มีประสิทธิภาพเพียงพอสำหรับแอปพลิเคชันสมัยใหม่ที่ใช้ Canvas การทดสอบ JSPerf จํานวนหนึ่งตามที่อธิบายไว้ข้างต้นมีประสิทธิภาพแย่กว่าในอุปกรณ์เคลื่อนที่เมื่อเทียบกับเดสก์ท็อปอย่างมาก ซึ่งจํากัดประเภทของแอปข้ามอุปกรณ์ที่คาดว่าจะทํางานได้สําเร็จ
บทสรุป
โดยสรุปแล้ว บทความนี้ครอบคลุมเทคนิคการเพิ่มประสิทธิภาพที่มีประโยชน์อย่างครอบคลุม ซึ่งจะช่วยให้คุณพัฒนาโปรเจ็กต์แคนวาส HTML5 ที่มีประสิทธิภาพ เมื่อได้เรียนรู้สิ่งใหม่ๆ แล้ว ก็ไปเพิ่มประสิทธิภาพให้กับผลงานสุดเจ๋งของคุณได้เลย หรือหากตอนนี้คุณยังไม่มีเกมหรือแอปพลิเคชันที่จะเพิ่มประสิทธิภาพ ให้ดูแรงบันดาลใจจาก Chrome Experiments และ Creative JS
ข้อมูลอ้างอิง
- โหมดทันทีเทียบกับโหมดเก็บไว้
- บทความเกี่ยวกับ Canvas อื่นๆ ของ HTML5Rocks
- ส่วน Canvas ของ "สํารวจ HTML5"
- JSPerf ช่วยให้นักพัฒนาซอฟต์แวร์สร้างการทดสอบประสิทธิภาพ JS ได้
- Browserscope จัดเก็บข้อมูลประสิทธิภาพเบราว์เซอร์
- JSPerfView ซึ่งแสดงผลการทดสอบ JSPerf เป็นแผนภูมิ
- บล็อกโพสต์ของ Simon เกี่ยวกับการล้างแคนวาส และหนังสือ HTML5 Unleashed ซึ่งมีบทเกี่ยวกับประสิทธิภาพของ Canvas
- บล็อกโพสต์ของ Sebastian เกี่ยวกับประสิทธิภาพการแสดงผลระดับพิกเซลย่อย
- การบรรยายของ Ben เกี่ยวกับการเพิ่มประสิทธิภาพโปรแกรมจำลอง NES ของ JS
- เครื่องมือวิเคราะห์ Canvas ใหม่ในเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome