2011-06-04 36 views
65

Có bất kỳ chức năng định thời nào trong JavaScript với độ phân giải micro giây không?Thời gian vi phân trong JavaScript

Tôi biết về timer.js dành cho Chrome và tôi hy vọng sẽ có giải pháp cho các trình duyệt thân thiện khác như Firefox, Safari, Opera, Epiphany, Konqueror, v.v. Tôi không quan tâm hỗ trợ bất kỳ IE nào, nhưng câu trả lời bao gồm IE được chào đón.

(Căn cứ vào độ chính xác kém thời gian millisecond trong JS, tôi không giữ hơi thở của tôi về thế này!)

Cập nhật: timer.js quảng cáo phân giải micro, nhưng nó chỉ đơn giản là sẽ nhân đọc millisecond 1.000. Được xác minh bằng kiểm tra và kiểm tra mã. Thất vọng. : [

+2

Bạn đang cố gắng để làm trong một trình duyệt mà đòi hỏi độ chính xác micro? Nói chung, đảm bảo hiệu suất hoạt động của các trình duyệt không phải là chính xác. – Yuliy

+3

Sẽ không xảy ra. Bạn không thể tin tưởng độ chính xác micro giây ngay cả khi nó tồn tại. Trường hợp sử dụng vững chắc duy nhất tôi có thể tưởng tượng là khách hàng bản địa trong chrome nhưng sau đó bạn không quan tâm đến JS API. Cũng yêu thương điều trị "Epiphany" như một trình duyệt lớp học đầu tiên và bỏ qua IE. – Raynos

+0

@Yuliy Không có lý do gì/không/có sẵn trong trình duyệt. Dưới đây là một số ví dụ về thời gian µs sẽ hữu ích: các ứng dụng web thời gian thực, trò chơi HTML5 và trình giả lập. – mwcz

Trả lời

87

Như được đề cập trong câu trả lời của Mark Rejhon, có một API có sẵn trong các trình duyệt hiện đại cho thấy dữ liệu thời gian phân giải dưới miligiây đến tập lệnh: W3C High Resolution Timer, aka window.performance.now().

now() là tốt hơn so với truyền thống Date.getTime() theo hai cách quan trọng:

  1. now() là một đôi với độ phân giải submillisecond đại diện cho số mili giây kể từ khi bắt đầu điều hướng của trang. Nó trả về số micro giây trong phân số (ví dụ: giá trị 1000.123 là 1 giây và 123 micro giây).

  2. now() tăng đơn điệu. Điều này quan trọng là Date.getTime() có thể có thể nhảy về phía trước hoặc thậm chí lạc hậu trong các cuộc gọi tiếp theo. Đáng chú ý, nếu thời gian hệ thống của hệ điều hành được cập nhật (ví dụ: đồng bộ hóa đồng hồ nguyên tử), Date.getTime() cũng được cập nhật. now() được đảm bảo luôn tăng lên đơn điệu, vì vậy nó không bị ảnh hưởng bởi thời gian hệ thống của hệ điều hành - nó sẽ luôn là thời gian đồng hồ (giả sử đồng hồ treo tường của bạn không phải là nguyên tử ...).

now() thể được sử dụng trong hầu hết mọi nơi mà new Date.getTime(), + new DateDate.now() đang có. Trường hợp ngoại lệ là Datenow() lần không kết hợp, vì Date được dựa trên unix-epoch (số mili giây từ năm 1970), trong khi now() là số mili giây kể từ khi điều hướng trang của bạn bắt đầu (vì vậy nó sẽ nhỏ hơn nhiều so với Date) .

now() được hỗ trợ trong Chrome ổn định, Firefox 15+ và IE10. Ngoài ra còn có một số polyfills có sẵn.

+1

các polyfill sẽ được sử dụng nhiều nhất Date.now(), vì vậy đây vẫn là tùy chọn tốt nhất xem xét IE9 và hàng triệu người dùng, tại sao trộn thư viện của bên thứ ba sau đó –

+1

Đồng hồ treo tường * của tôi là * nguyên tử. – programmer5000

+1

'new Date.getTime()' không phải là một điều. 'new Date(). getTime()' là. –

3

Câu trả lời là "không", nói chung. Nếu bạn đang sử dụng JavaScript trong một số môi trường phía máy chủ (nghĩa là, không phải trong trình duyệt), thì tất cả các phiên cược đều bị tắt và bạn có thể thử làm bất cứ điều gì bạn muốn.

chỉnh sửa — câu trả lời này là cũ; các tiêu chuẩn đã tiến triển và các cơ sở mới hơn có sẵn như là các giải pháp cho vấn đề thời gian chính xác. Mặc dù vậy, cần nhớ rằng bên ngoài miền của một hệ điều hành thời gian thực thực sự, mã không đặc quyền thông thường đã hạn chế quyền kiểm soát truy cập của nó để tính toán tài nguyên. Hiệu suất đo không giống nhau (nhất thiết) là dự đoán hiệu suất.

15

Có bây giờ là một phương pháp mới để đo lường micro trong javascript: http://gent.ilcore.com/2012/06/better-timer-for-javascript.html

Tuy nhiên, trong quá khứ, tôi tìm thấy một phương pháp thô nhận được độ chính xác 0,1 phần nghìn giây trong JavaScript ra khỏi một timer millisecond. Không thể nào? Không. Hãy đọc:

Tôi đang thực hiện một số thử nghiệm có độ chính xác cao yêu cầu độ chính xác hẹn giờ tự kiểm tra và thấy rằng tôi có thể nhận được độ chính xác 0,1 mili giây với một số trình duyệt nhất định trên một số hệ thống nhất định.

Tôi thấy rằng trong các trình duyệt web tăng tốc GPU hiện đại trên các hệ thống nhanh (ví dụ: lõi tứ i7, trong đó một số lõi không hoạt động, chỉ cửa sổ trình duyệt) - Giờ đây tôi có thể tin tưởng bộ tính giờ chính xác đến mili giây. Trong thực tế, nó trở nên rất chính xác trên một hệ thống i7 nhàn rỗi, tôi đã có thể nhận được chính xác cùng một phần nghìn giây, hơn 1000 lần thử. Chỉ khi tôi đang cố gắng làm những việc như tải trang web bổ sung, hoặc khác, độ chính xác mili giây giảm xuống (Và tôi có thể nắm bắt được độ chính xác bị suy giảm của chính mình bằng cách thực hiện kiểm tra trước và sau, để xem liệu thời gian xử lý của tôi đột nhiên kéo dài đến 1 hoặc nhiều mili giây - điều này giúp tôi làm mất hiệu lực các kết quả có thể bị ảnh hưởng bất lợi bởi biến động CPU).

Nó trở nên chính xác trong một số trình duyệt tăng tốc GPU trên hệ thống quad-core i7 (khi cửa sổ trình duyệt là cửa sổ duy nhất), tôi thấy mình muốn truy cập bộ đếm thời gian chính xác 0,1ms trong JavaScript, tính chính xác cuối cùng cũng có trên một số hệ thống duyệt cao cấp để thực hiện độ chính xác của bộ đếm thời gian như vậy đối với một số loại ứng dụng thích hợp đòi hỏi độ chính xác cao và nơi ứng dụng có thể tự xác minh độ lệch chính xác.

Rõ ràng nếu bạn đang thực hiện nhiều lần chuyền, bạn có thể chỉ cần chạy nhiều vé (ví dụ 10 vé) rồi chia cho 10 để có độ chính xác 0,1 mili giây. Đó là một phương pháp phổ biến để có độ chính xác cao hơn - thực hiện nhiều lần truyền và chia tổng thời gian cho số lần vượt qua.

BAO GIỜ ...Nếu tôi chỉ có thể làm một đường chuyền chuẩn duy nhất của một thử nghiệm cụ thể do một tình huống độc đáo khác thường, tôi phát hiện ra rằng tôi có thể nhận được 0,1 (Và đôi khi 0.01ms) chính xác bằng cách làm này:

Khởi/Hiệu chuẩn:

  1. Chạy vòng lặp bận để chờ cho đến khi bộ đếm thời gian tăng đến mili giây tiếp theo (sắp xếp bộ hẹn giờ đến đầu khoảng thời gian mili giây tiếp theo) Vòng lặp bận này kéo dài dưới một phần nghìn giây.
  2. Chạy vòng lặp bận khác để tăng bộ đếm trong khi chờ bộ hẹn giờ tăng. Bộ đếm cho bạn biết số lượng bộ đếm đã xảy ra trong một mili giây. Vòng lặp bận này kéo dài một mili giây đầy đủ.
  3. Lặp lại các bước trên, cho đến khi các con số trở nên cực kỳ ổn định (thời gian tải, trình biên dịch JIT, v.v.). 4. CHÚ Ý: Độ ổn định của số cho bạn độ chính xác có thể đạt được trên hệ thống không hoạt động. Bạn có thể tính toán phương sai, nếu bạn cần tự kiểm tra độ chính xác. Các chênh lệch lớn hơn trên một số trình duyệt và nhỏ hơn trên các trình duyệt khác. Lớn hơn trên các hệ thống nhanh hơn và chậm hơn trên các hệ thống chậm hơn. Sự nhất quán cũng thay đổi. Bạn có thể biết trình duyệt nào phù hợp/chính xác hơn các trình duyệt khác. Hệ thống chậm chạp và hệ thống bận rộn sẽ dẫn đến chênh lệch lớn hơn giữa các lần khởi tạo. Điều này có thể cho bạn cơ hội hiển thị thông báo cảnh báo nếu trình duyệt không cung cấp cho bạn đủ độ chính xác để cho phép đo 0.1ms hoặc 0.01ms. Hẹn giờ skew có thể là một vấn đề, nhưng một số số nguyên mili giây tính giờ trên một số hệ thống tăng khá chính xác (khá đúng trên dấu chấm), điều này sẽ dẫn đến các giá trị hiệu chuẩn rất nhất quán mà bạn có thể tin tưởng.
  4. Lưu giá trị truy cập cuối cùng (hoặc trung bình của vài hiệu chỉnh cuối cùng đi)

Điểm chuẩn một đường chuyền qua phụ millisecond chính xác:

  1. Chạy một vòng lặp bận rộn để chờ cho đến khi gia hẹn giờ đến mili giây tiếp theo (sắp xếp bộ hẹn giờ để bắt đầu khoảng thời gian mili giây tiếp theo). Vòng lặp bận này kéo dài dưới một phần nghìn giây.
  2. Thực hiện tác vụ bạn muốn chuẩn xác chính xác thời gian.
  3. Kiểm tra bộ hẹn giờ. Điều này cung cấp cho bạn số nguyên mili giây.
  4. Chạy vòng lặp bận cuối cùng để tăng bộ đếm trong khi chờ bộ hẹn giờ tăng. Vòng lặp bận này kéo dài dưới một phần nghìn giây.
  5. Chia giá trị bộ đếm này, theo giá trị bộ đếm ban đầu từ khởi tạo.
  6. Bây giờ bạn đã nhận được phần thập phân của mili giây !!!!!!!!

CẢNH BÁO: Vòng lặp bận không được khuyến nghị trong trình duyệt web, nhưng may mắn thay, các vòng bận này chạy dưới 1 mili giây mỗi lần và chỉ chạy một vài lần.

Biến như biên dịch JIT và biến động CPU thêm không chính xác lớn, nhưng nếu bạn chạy nhiều lần khởi tạo, bạn sẽ có đầy đủ tính năng động, và cuối cùng bộ đếm được giải quyết cho một cái gì đó rất chính xác. Hãy chắc chắn rằng tất cả các vòng lặp bận rộn là chính xác cùng một chức năng cho tất cả các trường hợp, do đó sự khác biệt trong các vòng bận rộn không dẫn đến sự khác biệt. Hãy chắc chắn rằng tất cả các dòng mã được thực hiện nhiều lần trước khi bạn bắt đầu tin tưởng các kết quả, để cho phép các trình biên dịch JIT đã ổn định với một biên dịch lại động đầy đủ (dynarec).

Trong thực tế, tôi đã chứng kiến ​​độ chính xác tiếp cận micro giây trên nhất định hệ thống, nhưng tôi vẫn chưa tin tưởng. Nhưng 0.Độ chính xác 1 mili giây xuất hiện để hoạt động khá đáng tin cậy, trên hệ thống bốn lõi nhàn rỗi, nơi tôi là trang trình duyệt duy nhất. Tôi đã đến một trường hợp thử nghiệm khoa học, nơi tôi chỉ có thể thực hiện một lần (do các biến duy nhất xảy ra) và cần thời gian chính xác mỗi lần vượt qua, thay vì tính trung bình nhiều lần lặp lại, vì vậy đó là lý do tôi làm điều này.

Tôi đã thực hiện một số tiền vượt và vé giả (cũng để giải quyết dynarec), để xác minh độ chính xác 0,1ms (giữ vững trong vài giây), sau đó giữ tay khỏi bàn phím/chuột, trong khi điểm chuẩn xuất hiện , sau đó đã thực hiện một số bài đăng để xác minh độ tin cậy của độ chính xác 0,1ms (vẫn vững chắc một lần nữa). Điều này cũng xác minh rằng những thứ như thay đổi trạng thái quyền lực, hoặc những thứ khác, đã không xảy ra giữa trước và sau, can thiệp vào kết quả. Lặp lại bài kiểm tra trước và sau bài kiểm tra giữa mỗi điểm chuẩn. Sau đó, tôi đã gần như chắc chắn kết quả ở giữa là chính xác. Không có gì đảm bảo, tất nhiên, nhưng nó cho thấy chính xác < 0.1ms chính xác là có thể trong một số trường hợp trong một trình duyệt web.

Phương pháp này chỉ hữu ích trong các trường hợp rất, rất thích hợp. Mặc dù vậy, theo nghĩa đen, nó sẽ không thể bảo đảm 100% một cách vô hạn, bạn có thể đạt được độ chính xác khá đáng tin cậy, và thậm chí cả độ chính xác khoa học khi kết hợp với nhiều lớp xác minh nội bộ và bên ngoài.

+3

Nó được sử dụng để phức tạp để làm thời gian với độ chính xác cao bởi vì tất cả chúng tôi đã có 'Date.now()' hoặc '+ new Date()'. Nhưng bây giờ chúng ta có 'performance.now()'. Mặc dù rõ ràng bạn đã tìm thấy một số cách thú vị để hack ra nhiều khả năng hơn, câu trả lời này về cơ bản là lỗi thời. Ngoài ra, không khuyên bạn nên bất cứ điều gì liên quan đến vòng bận rộn. Đừng làm thế. Chúng ta không cần nhiều hơn thế. –

+0

Hầu hết các trình duyệt đều giảm độ chính xác của hoạt động performance.now() của họ để tạm thời giảm thiểu thời gian tấn công bộ nhớ cache. Tôi tự hỏi liệu câu trả lời này vẫn có ý nghĩa trong nghiên cứu bảo mật. –

0

Dưới đây là ví dụ hiển thị bộ hẹn giờ có độ phân giải cao cho nút .js:

function startTimer() { 
    const time = process.hrtime(); 
    return time; 
} 

function endTimer(time) { 
    function roundTo(decimalPlaces, numberToRound) { 
    return +(Math.round(numberToRound + `e+${decimalPlaces}`) + `e-${decimalPlaces}`); 
    } 
    const diff = process.hrtime(time); 
    const NS_PER_SEC = 1e9; 
    const result = (diff[0] * NS_PER_SEC + diff[1]); // Result in Nanoseconds 
    const elapsed = result * 0.0000010; 
    return roundTo(6, elapsed); // Result in milliseconds 
} 

Cách sử dụng:

const start = startTimer(); 

console.log('test'); 

console.log(`Time since start: ${endTimer(start)} ms`); 

Thông thường, bạn có thể sử dụng:

console.time('Time since start'); 

console.log('test'); 

console.timeEnd('Time since start'); 

Nếu bạn đang thời gian các phần của mã mà liên quan đến vòng lặp, bạn không thể truy cập với giá trị của console.timeEnd() để thêm kết quả hẹn giờ của bạn với nhau. Bạn có thể, nhưng nó nhận được khó chịu bởi vì bạn phải tiêm giá trị của biến lặp của bạn, chẳng hạn như i, và thiết lập một điều kiện để phát hiện nếu vòng lặp được thực hiện.

Dưới đây là một ví dụ vì nó có thể hữu ích:

const num = 10; 

console.time(`Time til ${num}`); 

for (let i = 0; i < num; i++) { 
    console.log('test'); 
    if ((i+1) === num) { console.timeEnd(`Time til ${num}`); } 
    console.log('...additional steps'); 
} 

Cite: https://nodejs.org/api/process.html#process_process_hrtime_time

Các vấn đề liên quan