Nếu đã sử dụng requestAnimationFrame
, bạn sẽ thấy các bản vẽ được đồng bộ hoá với tốc độ làm mới của màn hình, tạo ra ảnh động có độ trung thực cao nhất có thể. Ngoài ra, bạn còn giúp người dùng giảm tiếng ồn của quạt CPU và tiết kiệm pin khi họ chuyển sang một thẻ khác.
Tuy nhiên, sắp có thay đổi đối với một phần API. Dấu thời gian được truyền vào hàm gọi lại của bạn đang thay đổi từ dấu thời gian Date.now()
thông thường thành số liệu đo lường có độ phân giải cao về mili giây dấu phẩy động kể từ khi mở trang. Nếu sử dụng giá trị này, bạn cần cập nhật mã dựa trên nội dung giải thích bên dưới.
Để rõ ràng hơn, tôi xin nói rõ vấn đề như sau:
// assuming requestAnimationFrame method has been normalized for all vendor prefixes..
requestAnimationFrame(function(timestamp){
// the value of timestamp is changing
});
Nếu đang sử dụng shim requestAnimFrame
phổ biến được cung cấp tại đây, thì bạn không sử dụng giá trị dấu thời gian. Bạn không cần làm gì cả. :)
Lý do
Tại sao? rAF giúp bạn đạt được tốc độ 60 khung hình/giây tối ưu và 60 khung hình/giây tương đương với 16, 7 mili giây/khung hình. Nhưng việc đo lường bằng số nguyên mili giây có nghĩa là chúng ta có độ chính xác là 1/16 đối với mọi thứ chúng ta muốn quan sát và nhắm đến.

Như bạn có thể thấy ở trên, thanh màu xanh dương thể hiện khoảng thời gian tối đa mà bạn có để thực hiện tất cả công việc trước khi vẽ một khung hình mới (ở tốc độ 60 khung hình/giây). Có thể bạn đang làm nhiều việc hơn 16 việc, nhưng với số nguyên mili giây, bạn chỉ có thể lên lịch và đo lường theo các mức tăng rất lớn đó. Như vậy là chưa đủ.
High Resolution Timer (Bộ hẹn giờ có độ phân giải cao) giải quyết vấn đề này bằng cách cung cấp một con số chính xác hơn nhiều:
Date.now() // 1337376068250
performance.now() // 20303.427000007
Bộ hẹn giờ có độ phân giải cao hiện có trong Chrome dưới dạng window.performance.webkitNow()
và giá trị này thường bằng với giá trị đối số mới được truyền vào lệnh gọi lại rAF. Sau khi thông số kỹ thuật phát triển thêm theo các tiêu chuẩn, phương thức này sẽ loại bỏ tiền tố và có sẵn thông qua performance.now()
.
Bạn cũng sẽ nhận thấy hai giá trị ở trên khác nhau nhiều cấp độ. performance.now()
là một phép đo mili giây dấu phẩy động kể từ khi trang cụ thể đó bắt đầu tải (cụ thể là performance.navigationStart
).
Đang sử dụng
Vấn đề chính là các thư viện ảnh động sử dụng mẫu thiết kế này:
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));
}
Bạn có thể dễ dàng chỉnh sửa để khắc phục vấn đề này... hãy mở rộng startTime
và now
để sử dụng window.performance.now()
.
this.startTime = window.performance.now ?
(performance.now() + performance.timing.navigationStart) :
Date.now();
Đây là cách triển khai khá đơn giản, không sử dụng phương thức now()
có tiền tố và cũng giả định hỗ trợ Date.now()
, không có trong IE8.
Phát hiện tính năng
Nếu không sử dụng mẫu trên và chỉ muốn xác định loại giá trị gọi lại mà bạn nhận được, bạn có thể sử dụng kỹ thuật này:
requestAnimationFrame(function(timestamp){
if (timestamp < 1e12){
// .. high resolution timer
} else {
// integer milliseconds since unix epoch
}
// ...
Việc kiểm tra if (timestamp < 1e12)
là một kiểm thử nhanh để xem chúng ta đang xử lý số lượng lớn đến mức nào. Về mặt kỹ thuật, điều này có thể là kết quả dương tính giả, nhưng chỉ khi một trang web mở liên tục trong 30 năm. Tuy nhiên, chúng ta không thể kiểm tra xem đó có phải là số dấu phẩy động hay không (thay vì được làm tròn thành số nguyên). Yêu cầu đủ bộ hẹn giờ có độ phân giải cao và bạn chắc chắn sẽ nhận được giá trị số nguyên tại một thời điểm nào đó.
Chúng tôi dự định sẽ triển khai thay đổi này trong Chrome 21. Vì vậy, nếu bạn đang tận dụng tham số gọi lại này, hãy nhớ cập nhật mã của mình!