Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat(cdk): make scheduler features configurable #1843

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions libs/cdk/internals/scheduler/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,9 @@ export {
forceFrameRate,
scheduleCallback,
} from './lib/scheduler';
export {
provideConcurrentSchedulerConfig as ɵprovideConcurrentSchedulerConfig,
withFramerate as ɵwithFramerate,
withInputPending as ɵwithInputPending,
} from './lib/scheduler.config';
export * from './lib/schedulerPriorities';
88 changes: 88 additions & 0 deletions libs/cdk/internals/scheduler/src/lib/scheduler.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { InjectionToken, Provider } from '@angular/core';
import { forceFrameRate, setInputPending } from './scheduler';

export type RX_ANGULAR_SCHEDULER_CONFIGS = 'Framerate' | 'InputPending';

interface RxSchedulerConfigFn {
kind: RX_ANGULAR_SCHEDULER_CONFIGS;
providers: Provider[];
}

const RX_SCHEDULER_DEFAULT_FPS = 60;

// set default to 60fps
forceFrameRate(RX_SCHEDULER_DEFAULT_FPS);

export const RX_SCHEDULER_FPS = new InjectionToken<number>(
'RX_SCHEDULER_FRAMERATE',
{
providedIn: 'root',
factory: () => RX_SCHEDULER_DEFAULT_FPS,
},
);

/**
* Provider function to specify a scheduler for `RxState` to perform state updates & emit new values.
* @param fps
*/
export function withFramerate(fps: number): unknown {
return {
kind: 'Framerate',
providers: [
{
provide: RX_SCHEDULER_FPS,
useFactory: () => {
forceFrameRate(fps);
return fps;
},
},
],
};
}

interface RxSchedulerInputPendingConfig {
enabled: boolean;
includeContinuous: boolean;
}

export const RX_SCHEDULER_INPUT_PENDING =
new InjectionToken<RxSchedulerInputPendingConfig>(
'RX_SCHEDULER_INPUT_PENDING',
);

/**

*/
export function withInputPending(
config: RxSchedulerInputPendingConfig = {
enabled: false,
includeContinuous: false,
},
): RxSchedulerConfigFn {
return {
kind: 'InputPending',
providers: [
{
provide: RX_SCHEDULER_INPUT_PENDING,
useFactory: () => {
// initialization logic here
setInputPending(config.enabled, config.includeContinuous);
return config;
},
},
],
};
}

/**
*
*/
export function provideConcurrentSchedulerConfig(
...configs: RxSchedulerConfigFn[]
): Provider[] {
return flatten(configs.map((c) => c.providers));
}

function flatten<T>(arr: T[][]): T[] {
return arr.reduce((acc, val) => acc.concat(val), []);
}
26 changes: 15 additions & 11 deletions libs/cdk/internals/scheduler/src/lib/scheduler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ let getCurrentTime: () => number;
const hasPerformanceNow =
typeof ɵglobal.performance === 'object' &&
typeof ɵglobal.performance.now === 'function';

let isInputPending = () => false;
if (hasPerformanceNow) {
const localPerformance = ɵglobal.performance;
getCurrentTime = () => localPerformance.now();
Expand Down Expand Up @@ -162,12 +162,14 @@ function workLoop(
currentTime = getCurrentTime();
if (typeof continuationCallback === 'function') {
currentTask.callback = continuationCallback;
advanceTimers(currentTime);
return true;
} else {
if (currentTask === peek(taskQueue)) {
pop(taskQueue);
}
advanceTimers(currentTime);
}
advanceTimers(currentTime);
} else {
pop(taskQueue);
}
Expand Down Expand Up @@ -308,25 +310,27 @@ let needsPaint = false;
let queueStartTime = -1;

function shouldYieldToHost() {
if (needsPaint) {
if (needsPaint || isInputPending()) {
// There's a pending paint (signaled by `requestPaint`). Yield now.
return true;
}
const timeElapsed = getCurrentTime() - queueStartTime;
if (timeElapsed < yieldInterval) {
// The main thread has only been blocked for a really short amount of time;
// smaller than a single frame. Don't yield yet.
return false;
}

// `isInputPending` isn't available. Yield now.
return true;
return timeElapsed >= yieldInterval;
}

function requestPaint() {
needsPaint = true;
}

export function setInputPending(enable: boolean, includeContinuous = false) {
if (enable && ɵglobal.navigator?.scheduling?.isInputPending) {
isInputPending = () =>
ɵglobal.navigator.scheduling.isInputPending({ includeContinuous });
} else {
isInputPending = () => false;
}
}

export function forceFrameRate(fps) {
if (fps < 0 || fps > 125) {
if (typeof ngDevMode === 'undefined' || ngDevMode) {
Expand Down
5 changes: 5 additions & 0 deletions libs/cdk/render-strategies/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,8 @@ export {
export { onStrategy } from './lib/onStrategy';
export { strategyHandling } from './lib/strategy-handling';
export { RxStrategyProvider } from './lib/strategy-provider.service';
export {
ɵprovideConcurrentSchedulerConfig as provideConcurrentSchedulerConfig,
ɵwithInputPending as withExperimentalInputPending,
ɵwithFramerate as withFramerate,
} from '@rx-angular/cdk/internals/scheduler';
18 changes: 9 additions & 9 deletions libs/cdk/render-strategies/src/lib/concurrent-strategies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const immediateStrategy: RxStrategyCredentials = {
ngZone,
priority: PriorityLevel.ImmediatePriority,
scope,
})
}),
);
},
};
Expand All @@ -42,7 +42,7 @@ const userBlockingStrategy: RxStrategyCredentials = {
ngZone,
priority: PriorityLevel.UserBlockingPriority,
scope,
})
}),
);
},
};
Expand All @@ -57,7 +57,7 @@ const normalStrategy: RxStrategyCredentials = {
ngZone,
priority: PriorityLevel.NormalPriority,
scope,
})
}),
);
},
};
Expand All @@ -72,7 +72,7 @@ const lowStrategy: RxStrategyCredentials = {
ngZone,
priority: PriorityLevel.LowPriority,
scope,
})
}),
);
},
};
Expand All @@ -87,7 +87,7 @@ const idleStrategy: RxStrategyCredentials = {
ngZone,
priority: PriorityLevel.IdlePriority,
scope,
})
}),
);
},
};
Expand All @@ -99,7 +99,7 @@ function scheduleOnQueue<T>(
scope: coalescingObj;
delay?: number;
ngZone: NgZone;
}
},
): MonoTypeOperatorFunction<T> {
const scope = (options.scope as Record<string, unknown>) || {};
return (o$: Observable<T>): Observable<T> =>
Expand All @@ -115,14 +115,14 @@ function scheduleOnQueue<T>(
coalescingManager.remove(scope);
subscriber.next(v);
},
{ delay: options.delay, ngZone: options.ngZone }
{ delay: options.delay, ngZone: options.ngZone },
);
return () => {
coalescingManager.remove(scope);
cancelCallback(task);
};
}).pipe(mapTo(v))
)
}).pipe(mapTo(v)),
),
);
}

Expand Down
Loading