หากเคยใช้ requestAnimationFrame
คุณจะได้เห็นภาพวาดที่ซิงค์กับอัตราการรีเฟรชของหน้าจอ ซึ่งทำให้ได้ภาพเคลื่อนไหวที่สมจริงที่สุด นอกจากนี้ คุณยังช่วยประหยัดเสียงพัดลมของ CPU และพลังงานแบตเตอรี่ของผู้ใช้เมื่อผู้ใช้เปลี่ยนไปใช้แท็บอื่น
อย่างไรก็ตาม เรากําลังจะมีการเปลี่ยนแปลง API บางส่วน การประทับเวลาที่ส่งไปยังฟังก์ชันการเรียกกลับจะเปลี่ยนจากการประทับเวลาแบบ Date.now()
ทั่วไปเป็นการวัดความละเอียดสูงของจำนวนมิลลิวินาทีแบบทศนิยมลอยตัวนับตั้งแต่เปิดหน้าเว็บ หากใช้ค่านี้ คุณจะต้องอัปเดตโค้ดตามคำอธิบายด้านล่าง
เราขออธิบายให้ชัดเจนว่า
// assuming requestAnimationFrame method has been normalized for all vendor prefixes..
requestAnimationFrame(function(timestamp){
// the value of timestamp is changing
});
หากคุณใช้requestAnimFrame
ชิมทั่วไปที่ระบุไว้ที่นี่ แสดงว่าคุณไม่ได้ใช้ค่าการประทับเวลา คุณไม่ตกข่าวเลย :)
ทำไม
เหตุผล rAF จะช่วยให้คุณได้รับ 60 FPS ที่ดีที่สุด ซึ่งเหมาะที่สุด และ 60 FPS หมายถึง 16.7 มิลลิวินาทีต่อเฟรม แต่การวัดด้วยจำนวนเต็มในหน่วยมิลลิวินาทีหมายความว่าเรามีความแม่นยำ 1/16 สำหรับทุกสิ่งที่เราต้องการสังเกตและกำหนดเป้าหมาย
ดังที่เห็นด้านบน แถบสีน้ำเงินแสดงถึงเวลาสูงสุดที่คุณต้องทำงานทั้งหมดก่อนที่จะวาดเฟรมใหม่ (ที่ 60 fps) คุณอาจทำสิ่งต่างๆ มากกว่า 16 อย่าง แต่การใช้มิลลิวินาทีแบบจำนวนเต็มจะทำให้คุณกำหนดเวลาและวัดผลได้เฉพาะแบบเพิ่มขึ้นทีละมาก คุณภาพยังไม่ดีพอ
ตัวจับเวลาความละเอียดสูงช่วยแก้ปัญหานี้ด้วยการแสดงตัวเลขที่แม่นยำกว่ามาก ดังนี้
Date.now() // 1337376068250
performance.now() // 20303.427000007
ปัจจุบันตัวจับเวลาความละเอียดสูงพร้อมใช้งานใน Chrome เป็น window.performance.webkitNow()
และโดยทั่วไปค่านี้จะเท่ากับค่าอาร์กิวเมนต์ใหม่ที่ส่งไปยังการเรียกกลับ rAF เมื่อข้อกำหนดได้รับการพัฒนาตามมาตรฐานเพิ่มเติม วิธีการนี้จะยกเลิกคำนำหน้าและพร้อมใช้งานผ่าน performance.now()
นอกจากนี้ คุณจะสังเกตเห็นว่าค่าสองค่าข้างต้นเป็นลำดับของขนาดที่แตกต่างกัน performance.now()
คือการวัดค่ามิลลิวินาทีแบบทศนิยมลอยตัวนับตั้งแต่หน้าเว็บนั้นๆ เริ่มโหลด (performance.navigationStart
นั่นเอง)
ใช้งานอยู่
ปัญหาหลักที่ทำให้เกิดภาพตัดคือไลบรารีภาพเคลื่อนไหวที่ใช้รูปแบบการออกแบบนี้
function MyAnimation(duration) {
this.startTime = Date.now();
this.duration = duration;
requestAnimFrame(this.tick.bind(this));
}
MyAnimation.prototype.tick = function(time) {
var now = Date.now();
if (time > now) {
this.dispatchEvent("ended");
return;
}
...
requestAnimFrame(this.tick.bind(this));
}
การแก้ไขเพื่อแก้ไขปัญหานี้นั้นง่ายมาก เพียงเพิ่ม startTime
และ now
เพื่อใช้ window.performance.now()
this.startTime = window.performance.now ?
(performance.now() + performance.timing.navigationStart) :
Date.now();
วิธีนี้เป็นการใช้งานที่ค่อนข้างตรงไปตรงมา ไม่ใช้เมธอด now()
นำหน้าและยังรองรับ Date.now()
ซึ่งไม่ได้อยู่ใน IE8 ด้วย
การตรวจหาฟีเจอร์
หากคุณไม่ได้ใช้รูปแบบข้างต้นและต้องการระบุประเภทของค่าการเรียกกลับที่ได้รับ ให้ใช้เทคนิคนี้
requestAnimationFrame(function(timestamp){
if (timestamp < 1e12){
// .. high resolution timer
} else {
// integer milliseconds since unix epoch
}
// ...
การตรวจสอบ if (timestamp < 1e12)
เป็นการตรวจสอบคร่าวๆ เพื่อดูว่าจำนวนที่เรากำลังจัดการมีมากน้อยเพียงใด ในทางเทคนิคแล้ว การตรวจอาจให้ผลบวกปลอมได้ในกรณีที่หน้าเว็บเปิดอยู่อย่างต่อเนื่องเป็นเวลา 30 ปีเท่านั้น แต่เราไม่สามารถทดสอบว่าค่านี้เป็นตัวเลขทศนิยม (ไม่ใช่ปัดเศษเป็นจำนวนเต็ม) หรือไม่ ขอให้มีตัวจับเวลาความละเอียดสูงมากพอ และคุณจะได้ค่าจำนวนเต็มเมื่อใดก็ตาม
เราวางแผนที่จะนำการเปลี่ยนแปลงนี้ไปใช้ใน Chrome 21 ดังนั้น หากคุณใช้ประโยชน์จากพารามิเตอร์ Callback นี้แล้ว โปรดอัปเดตโค้ด