fix(js): make performance.now() monotonic
The old sub-millisecond bump (_sub += 0.1) was uncapped, so after >10 calls in one millisecond it exceeded 1.0; when the wall clock then ticked over and the bump reset to 0, now() returned a value below the previous call. Track the last returned value and never go below it (advance by a tiny epsilon when the clock has not moved past it). Fixes #497
This commit is contained in:
1 parent
8078cc3070
commit
cdab919599
2 files changed
+21
-3
No files matched your search
Vendored
+8
-3
@@ -5360,11 +5360,16 @@ globalThis.XMLSerializer = class XMLSerializer {
|
|||||||
};
|
};
|
||||||
globalThis.performance = globalThis.performance || {
|
globalThis.performance = globalThis.performance || {
|
||||||
now: (function() {
|
now: (function() {
|
||||||
var _lastMs = -1, _sub = 0;
|
// Monotonically non-decreasing: return the wall-clock offset, but never a
|
||||||
|
// value below the last one. The previous version added an uncapped per-call
|
||||||
|
// sub-millisecond bump that could exceed 1.0, so when the millisecond then
|
||||||
|
// ticked over and the bump reset to 0 the result went backwards.
|
||||||
|
var _last = 0;
|
||||||
return function() {
|
return function() {
|
||||||
var ms = Date.now() - (globalThis.performance.timeOrigin || 0);
|
var ms = Date.now() - (globalThis.performance.timeOrigin || 0);
|
||||||
if (ms !== _lastMs) { _lastMs = ms; _sub = 0; } else { _sub += 0.1; }
|
if (ms > _last) _last = ms;
|
||||||
return ms + _sub;
|
else _last += 0.001; // same/earlier ms: advance by a tiny epsilon
|
||||||
|
return _last;
|
||||||
};
|
};
|
||||||
})(),
|
})(),
|
||||||
mark(){}, measure(){},
|
mark(){}, measure(){},
|
||||||
|
|||||||
@@ -1317,6 +1317,19 @@ mod tests {
|
|||||||
rt
|
rt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn performance_now_is_monotonic_under_bursty_calls() {
|
||||||
|
let mut rt = setup_runtime("<html><body></body></html>");
|
||||||
|
// Hammer performance.now() so many calls land in the same millisecond and
|
||||||
|
// the wall clock rolls over repeatedly; the value must never go backwards.
|
||||||
|
let violations = rt
|
||||||
|
.evaluate(
|
||||||
|
"(function(){var prev=-Infinity, bad=0; for(var i=0;i<500000;i++){var t=performance.now(); if(t<prev) bad++; prev=t;} return bad;})()",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(violations.as_f64(), Some(0.0), "performance.now() went backwards");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_document_title() {
|
fn test_document_title() {
|
||||||
let mut rt = setup_runtime("<html><head><title>Test</title></head><body></body></html>");
|
let mut rt = setup_runtime("<html><head><title>Test</title></head><body></body></html>");
|
||||||
|
|||||||
Reference in new issue
Block a user