mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
chore: simplify doTick (#31196)
This commit is contained in:
parent
826343b8a0
commit
dd3a41287e
@ -39,22 +39,19 @@ export class Clock {
|
|||||||
|
|
||||||
async runToNextTimer(): Promise<number> {
|
async runToNextTimer(): Promise<number> {
|
||||||
this._assertInstalled();
|
this._assertInstalled();
|
||||||
await this._browserContext.addInitScript(`globalThis.__pwClock.clock.next()`);
|
this._now = await this._evaluateInFrames(`globalThis.__pwClock.clock.next()`);
|
||||||
this._now = await this._evaluateInFrames(`globalThis.__pwClock.clock.nextAsync()`);
|
|
||||||
return this._now;
|
return this._now;
|
||||||
}
|
}
|
||||||
|
|
||||||
async runAllTimers(): Promise<number> {
|
async runAllTimers(): Promise<number> {
|
||||||
this._assertInstalled();
|
this._assertInstalled();
|
||||||
await this._browserContext.addInitScript(`globalThis.__pwClock.clock.runAll()`);
|
this._now = await this._evaluateInFrames(`globalThis.__pwClock.clock.runAll()`);
|
||||||
this._now = await this._evaluateInFrames(`globalThis.__pwClock.clock.runAllAsync()`);
|
|
||||||
return this._now;
|
return this._now;
|
||||||
}
|
}
|
||||||
|
|
||||||
async runToLastTimer(): Promise<number> {
|
async runToLastTimer(): Promise<number> {
|
||||||
this._assertInstalled();
|
this._assertInstalled();
|
||||||
await this._browserContext.addInitScript(`globalThis.__pwClock.clock.runToLast()`);
|
this._now = await this._evaluateInFrames(`globalThis.__pwClock.clock.runToLast()`);
|
||||||
this._now = await this._evaluateInFrames(`globalThis.__pwClock.clock.runToLastAsync()`);
|
|
||||||
return this._now;
|
return this._now;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,8 +82,8 @@ export class Clock {
|
|||||||
|
|
||||||
async runFor(time: number | string): Promise<number> {
|
async runFor(time: number | string): Promise<number> {
|
||||||
this._assertInstalled();
|
this._assertInstalled();
|
||||||
await this._browserContext.addInitScript(`globalThis.__pwClock.clock.tick(${JSON.stringify(time)})`);
|
await this._browserContext.addInitScript(`globalThis.__pwClock.clock.recordTick(${JSON.stringify(time)})`);
|
||||||
this._now = await this._evaluateInFrames(`globalThis.__pwClock.clock.tickAsync(${JSON.stringify(time)})`);
|
this._now = await this._evaluateInFrames(`globalThis.__pwClock.clock.tick(${JSON.stringify(time)})`);
|
||||||
return this._now;
|
return this._now;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -89,149 +89,59 @@ export class ClockController {
|
|||||||
return this._now - this._adjustedSystemTime - this.start;
|
return this._now - this._adjustedSystemTime - this.start;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _doTick(tickValue: number | string, isAsync: boolean, resolve?: (time: number) => void, reject?: (error: Error) => void): number | undefined {
|
private async _doTick(msFloat: number): Promise<number> {
|
||||||
const msFloat =
|
|
||||||
typeof tickValue === 'number'
|
|
||||||
? tickValue
|
|
||||||
: parseTime(tickValue);
|
|
||||||
const ms = Math.floor(msFloat);
|
|
||||||
let tickTo = this._now + ms;
|
|
||||||
|
|
||||||
if (msFloat < 0)
|
if (msFloat < 0)
|
||||||
throw new TypeError('Negative ticks are not supported');
|
throw new TypeError('Negative ticks are not supported');
|
||||||
|
|
||||||
|
const ms = Math.floor(msFloat);
|
||||||
|
let tickTo = this._now + ms;
|
||||||
let tickFrom = this._now;
|
let tickFrom = this._now;
|
||||||
let previous = this._now;
|
let previous = this._now;
|
||||||
// ESLint fails to detect this correctly
|
let firstException: Error | undefined;
|
||||||
/* eslint-disable prefer-const */
|
|
||||||
let timer;
|
|
||||||
let firstException: Error;
|
|
||||||
let oldNow: number;
|
|
||||||
let nextPromiseTick: (() => void) | null;
|
|
||||||
let compensationCheck: () => void;
|
|
||||||
let postTimerCall: () => void;
|
|
||||||
|
|
||||||
this._duringTick = true;
|
this._duringTick = true;
|
||||||
|
|
||||||
// perform microtasks
|
|
||||||
oldNow = this._now;
|
|
||||||
if (oldNow !== this._now) {
|
|
||||||
// compensate for any setSystemTime() call during microtask callback
|
|
||||||
tickFrom += this._now - oldNow;
|
|
||||||
tickTo += this._now - oldNow;
|
|
||||||
}
|
|
||||||
|
|
||||||
const doTickInner = (): number | undefined => {
|
|
||||||
// perform each timer in the requested range
|
// perform each timer in the requested range
|
||||||
timer = this._firstTimerInRange(tickFrom, tickTo);
|
let timer = this._firstTimerInRange(tickFrom, tickTo);
|
||||||
while (timer && tickFrom <= tickTo) {
|
while (timer && tickFrom <= tickTo) {
|
||||||
if (this._timers.has(timer.id)) {
|
|
||||||
tickFrom = timer.callAt;
|
tickFrom = timer.callAt;
|
||||||
this._now = timer.callAt;
|
this._now = timer.callAt;
|
||||||
oldNow = this._now;
|
const oldNow = this._now;
|
||||||
try {
|
try {
|
||||||
this._callTimer(timer);
|
this._callTimer(timer);
|
||||||
|
await new Promise<void>(f => this._embedder.postTask(f));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
firstException = firstException || e;
|
firstException = firstException || e;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isAsync) {
|
|
||||||
// finish up after native setImmediate callback to allow
|
|
||||||
// all native es6 promises to process their callbacks after
|
|
||||||
// each timer fires.
|
|
||||||
this._embedder.postTask(nextPromiseTick!);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
compensationCheck();
|
|
||||||
}
|
|
||||||
postTimerCall();
|
|
||||||
}
|
|
||||||
|
|
||||||
// perform process.nextTick()s again
|
|
||||||
oldNow = this._now;
|
|
||||||
if (oldNow !== this._now) {
|
|
||||||
// compensate for any setSystemTime() call during process.nextTick() callback
|
|
||||||
tickFrom += this._now - oldNow;
|
|
||||||
tickTo += this._now - oldNow;
|
|
||||||
}
|
|
||||||
this._duringTick = false;
|
|
||||||
|
|
||||||
// corner case: during runJobs new timers were scheduled which could be in the range [clock.now, tickTo]
|
|
||||||
timer = this._firstTimerInRange(tickFrom, tickTo);
|
|
||||||
if (timer) {
|
|
||||||
try {
|
|
||||||
this.tick(tickTo - this._now); // do it all again - for the remainder of the requested range
|
|
||||||
} catch (e) {
|
|
||||||
firstException = firstException || e;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// no timers remaining in the requested range: move the clock all the way to the end
|
|
||||||
this._now = tickTo;
|
|
||||||
}
|
|
||||||
if (firstException)
|
|
||||||
throw firstException;
|
|
||||||
|
|
||||||
if (isAsync)
|
|
||||||
resolve!(this._now);
|
|
||||||
else
|
|
||||||
return this._now;
|
|
||||||
};
|
|
||||||
|
|
||||||
nextPromiseTick =
|
|
||||||
isAsync ?
|
|
||||||
() => {
|
|
||||||
try {
|
|
||||||
compensationCheck();
|
|
||||||
postTimerCall();
|
|
||||||
doTickInner();
|
|
||||||
} catch (e) {
|
|
||||||
reject!(e);
|
|
||||||
}
|
|
||||||
} : null;
|
|
||||||
|
|
||||||
compensationCheck = () => {
|
|
||||||
// compensate for any setSystemTime() call during timer callback
|
// compensate for any setSystemTime() call during timer callback
|
||||||
if (oldNow !== this._now) {
|
if (oldNow !== this._now) {
|
||||||
tickFrom += this._now - oldNow;
|
tickFrom += this._now - oldNow;
|
||||||
tickTo += this._now - oldNow;
|
tickTo += this._now - oldNow;
|
||||||
previous += this._now - oldNow;
|
previous += this._now - oldNow;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
postTimerCall = () => {
|
|
||||||
timer = this._firstTimerInRange(previous, tickTo);
|
timer = this._firstTimerInRange(previous, tickTo);
|
||||||
previous = tickFrom;
|
previous = tickFrom;
|
||||||
};
|
|
||||||
|
|
||||||
return doTickInner();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tick(tickValue: string | number): number {
|
|
||||||
return this._doTick(tickValue, false)!;
|
|
||||||
}
|
|
||||||
|
|
||||||
async tickAsync(tickValue: string | number): Promise<number> {
|
|
||||||
await new Promise<void>(f => this._embedder.postTask(f));
|
|
||||||
return new Promise((resolve, reject) => this._doTick(tickValue, true, resolve, reject));
|
|
||||||
}
|
|
||||||
|
|
||||||
next() {
|
|
||||||
const timer = this._firstTimer();
|
|
||||||
if (!timer)
|
|
||||||
return this._now;
|
|
||||||
|
|
||||||
this._duringTick = true;
|
|
||||||
try {
|
|
||||||
this._now = timer.callAt;
|
|
||||||
this._callTimer(timer);
|
|
||||||
return this._now;
|
|
||||||
} finally {
|
|
||||||
this._duringTick = false;
|
this._duringTick = false;
|
||||||
}
|
this._now = tickTo;
|
||||||
|
if (firstException)
|
||||||
|
throw firstException;
|
||||||
|
|
||||||
|
return this._now;
|
||||||
}
|
}
|
||||||
|
|
||||||
async nextAsync() {
|
async recordTick(tickValue: string | number) {
|
||||||
await new Promise<void>(f => this._embedder.postTask(f));
|
const msFloat = parseTime(tickValue);
|
||||||
|
this._now += msFloat;
|
||||||
|
}
|
||||||
|
|
||||||
|
async tick(tickValue: string | number): Promise<number> {
|
||||||
|
return await this._doTick(parseTime(tickValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
async next() {
|
||||||
const timer = this._firstTimer();
|
const timer = this._firstTimer();
|
||||||
if (!timer)
|
if (!timer)
|
||||||
return this._now;
|
return this._now;
|
||||||
@ -241,45 +151,29 @@ export class ClockController {
|
|||||||
this._now = timer.callAt;
|
this._now = timer.callAt;
|
||||||
try {
|
try {
|
||||||
this._callTimer(timer);
|
this._callTimer(timer);
|
||||||
|
await new Promise<void>(f => this._embedder.postTask(f));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
err = e;
|
err = e;
|
||||||
}
|
}
|
||||||
this._duringTick = false;
|
this._duringTick = false;
|
||||||
|
|
||||||
await new Promise<void>(f => this._embedder.postTask(f));
|
|
||||||
if (err)
|
if (err)
|
||||||
throw err;
|
throw err;
|
||||||
return this._now;
|
return this._now;
|
||||||
}
|
}
|
||||||
|
|
||||||
runAll() {
|
async runToFrame() {
|
||||||
for (let i = 0; i < this._loopLimit; i++) {
|
|
||||||
const numTimers = this._timers.size;
|
|
||||||
if (numTimers === 0)
|
|
||||||
return this._now;
|
|
||||||
this.next();
|
|
||||||
}
|
|
||||||
|
|
||||||
const excessJob = this._firstTimer();
|
|
||||||
if (!excessJob)
|
|
||||||
return;
|
|
||||||
throw this._getInfiniteLoopError(excessJob);
|
|
||||||
}
|
|
||||||
|
|
||||||
runToFrame() {
|
|
||||||
return this.tick(this.getTimeToNextFrame());
|
return this.tick(this.getTimeToNextFrame());
|
||||||
}
|
}
|
||||||
|
|
||||||
async runAllAsync() {
|
async runAll() {
|
||||||
for (let i = 0; i < this._loopLimit; i++) {
|
for (let i = 0; i < this._loopLimit; i++) {
|
||||||
await new Promise<void>(f => this._embedder.postTask(f));
|
|
||||||
const numTimers = this._timers.size;
|
const numTimers = this._timers.size;
|
||||||
if (numTimers === 0)
|
if (numTimers === 0)
|
||||||
return this._now;
|
return this._now;
|
||||||
|
|
||||||
this.next();
|
await this.next();
|
||||||
}
|
}
|
||||||
await new Promise<void>(f => this._embedder.postTask(f));
|
|
||||||
|
|
||||||
const excessJob = this._firstTimer();
|
const excessJob = this._firstTimer();
|
||||||
if (!excessJob)
|
if (!excessJob)
|
||||||
@ -287,28 +181,11 @@ export class ClockController {
|
|||||||
throw this._getInfiniteLoopError(excessJob);
|
throw this._getInfiniteLoopError(excessJob);
|
||||||
}
|
}
|
||||||
|
|
||||||
runToLast() {
|
async runToLast() {
|
||||||
const timer = this._lastTimer();
|
const timer = this._lastTimer();
|
||||||
if (!timer)
|
if (!timer)
|
||||||
return this._now;
|
return this._now;
|
||||||
return this.tick(timer.callAt - this._now);
|
return await this.tick(timer.callAt - this._now);
|
||||||
}
|
|
||||||
|
|
||||||
runToLastAsync() {
|
|
||||||
return new Promise<number>((resolve, reject) => {
|
|
||||||
this._embedder.postTask(() => {
|
|
||||||
try {
|
|
||||||
const timer = this._lastTimer();
|
|
||||||
if (!timer) {
|
|
||||||
resolve(this._now);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.tickAsync(timer.callAt - this._now).then(resolve);
|
|
||||||
} catch (e) {
|
|
||||||
reject(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
@ -332,18 +209,15 @@ export class ClockController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jump(tickValue: string | number): number {
|
async jump(tickValue: string | number): Promise<number> {
|
||||||
const msFloat =
|
const msFloat = parseTime(tickValue);
|
||||||
typeof tickValue === 'number'
|
|
||||||
? tickValue
|
|
||||||
: parseTime(tickValue);
|
|
||||||
const ms = Math.floor(msFloat);
|
const ms = Math.floor(msFloat);
|
||||||
|
|
||||||
for (const timer of this._timers.values()) {
|
for (const timer of this._timers.values()) {
|
||||||
if (this._now + ms > timer.callAt)
|
if (this._now + ms > timer.callAt)
|
||||||
timer.callAt = this._now + ms;
|
timer.callAt = this._now + ms;
|
||||||
}
|
}
|
||||||
return this.tick(ms);
|
return await this.tick(ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
addTimer(options: { func: TimerHandler, type: TimerType, delay?: number | string, args?: () => any[] }): number {
|
addTimer(options: { func: TimerHandler, type: TimerType, delay?: number | string, args?: () => any[] }): number {
|
||||||
@ -524,9 +398,12 @@ function inRange(from: number, to: number, timer: Timer): boolean {
|
|||||||
* number of milliseconds. This is used to support human-readable strings passed
|
* number of milliseconds. This is used to support human-readable strings passed
|
||||||
* to clock.tick()
|
* to clock.tick()
|
||||||
*/
|
*/
|
||||||
function parseTime(str: string): number {
|
function parseTime(value: number | string): number {
|
||||||
if (!str)
|
if (typeof value === 'number')
|
||||||
|
return value;
|
||||||
|
if (!value)
|
||||||
return 0;
|
return 0;
|
||||||
|
const str = value;
|
||||||
|
|
||||||
const strings = str.split(':');
|
const strings = str.split(':');
|
||||||
const l = strings.length;
|
const l = strings.length;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user