FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

perf(core): cache CSS media query results until their inputs change by triniwiz · Pull Request #11505 · NativeScript/NativeScript · GitHub

Repository navigation

Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension .ts  (4) All 1 file type selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
4 changes: 4 additions & 0 deletions packages/core/application/application-common.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import type { ApplicationEventData, CssChangedEventData, DiscardedErrorEventData
import { applyAccessibilityCssToRoot, readyInitAccessibilityCssHelper, readyInitFontScale } from '../accessibility/accessibility-common';
import { getActiveWindow, getAppMainEntry, getAutoSystemAppearanceChanged, isAppInBackground, setActiveWindow, setAppInBackground, setAppMainEntry, setAutoSystemAppearanceChanged } from './helpers-common';
import { getNativeScriptGlobals } from '../globals/global-utils';
import { invalidateMediaQueryCache } from '../media-query-list';
import { SDK_VERSION } from '../utils/constants';
import type { NativeWindow, NativeWindowEventData, PrimaryWindowChangedEventData, WindowBase, WindowCloseEventData, WindowContentRequest, WindowContentResolver, WindowLayoutDirectionChangedEventData, WindowOpenEventData, WindowOpenOptions, WindowOrientationChangedEventData, WindowRole, WindowSystemAppearanceChangedEventData } from '../native-window';
import { NativeWindowEvents, WindowEvents } from '../native-window/native-window-interfaces';
Expand Down Expand Up @@ -670,6 +671,7 @@ export class ApplicationCommon {
* the change events, because app code observed the outgoing window's values.
*/
private syncTraitsFromWindow(nativeWindow: NativeWindow): void {
invalidateMediaQueryCache();
const orientation = nativeWindow.orientation();
if (orientation) {
if (this._orientation === undefined) {
Expand Down Expand Up @@ -970,6 +972,7 @@ export class ApplicationCommon {
}

this._orientation = value;
invalidateMediaQueryCache();

// Update metrics early enough regardless of the existence of root view
// Also, CSS will use the correct size values during update trigger
Expand Down Expand Up @@ -1030,6 +1033,7 @@ export class ApplicationCommon {
return;
}
this._systemAppearance = value;
invalidateMediaQueryCache();
this.systemAppearanceChanged(this.getRootView(), value);
this.notify(<SystemAppearanceChangedEventData>{
eventName: this.systemAppearanceChangedEvent,
Expand Down
39 changes: 38 additions & 1 deletion packages/core/media-query-list/index.spec.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { matchMedia, checkIfMediaQueryMatches, MediaQueryList } from '.';
import { matchMedia, checkIfMediaQueryMatches, checkIfMediaQueryMatchesCached, invalidateMediaQueryCache, MediaQueryList } from '.';
import { Screen } from '../platform';

describe('media-query-list', () => {
Expand All @@ -14,6 +14,43 @@ describe('media-query-list', () => {
});
});

describe('checkIfMediaQueryMatchesCached', () => {
const query = `only screen and (max-width: ${widthDIPs})`;

afterEach(() => {
vi.restoreAllMocks();
});

it('evaluates each query once until invalidated', async () => {
await Promise.resolve();
invalidateMediaQueryCache();
const evaluate = vi.spyOn(Screen.mainScreen, 'heightPixels', 'get');

expect(checkIfMediaQueryMatchesCached(query)).toBe(true);
const afterFirst = evaluate.mock.calls.length;
expect(checkIfMediaQueryMatchesCached(query)).toBe(true);
expect(checkIfMediaQueryMatchesCached(query)).toBe(true);
expect(evaluate).toHaveBeenCalledTimes(afterFirst);

invalidateMediaQueryCache();
expect(checkIfMediaQueryMatchesCached(query)).toBe(true);
expect(evaluate.mock.calls.length).toBeGreaterThan(afterFirst);
});

it('re-evaluates after the screen size changes without an orientation change', async () => {
expect(checkIfMediaQueryMatchesCached(query)).toBe(true);
await Promise.resolve();

const { widthPixels } = Screen.mainScreen;
const width = vi.spyOn(Screen.mainScreen, 'widthPixels', 'get').mockReturnValue(widthPixels * 2);
expect(checkIfMediaQueryMatchesCached(query)).toBe(false);
width.mockRestore();

await Promise.resolve();
expect(checkIfMediaQueryMatchesCached(query)).toBe(true);
});
});

describe('matchMedia', () => {
it('should return a MediaQueryList that matches the css media query', () => {
const matchMediaWrapper = () => matchMedia(`only screen and (max-width: ${widthDIPs})`);
Expand Down
45 changes: 44 additions & 1 deletion packages/core/media-query-list/index.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,49 @@ function checkIfMediaQueryMatches(mediaQueryString: string): boolean {
return matches;
}

// CSS matching asks the same queries for every view. Orientation and appearance changes go
// through invalidateMediaQueryCache; the screen size can change without either (a foldable's
// display, a window moved to another screen), so it is compared once per turn instead.
const cssQueryResults = new Map<string, boolean>();
let mediaQueryEpoch = 0;
let cachedScreenWidth: number;
let cachedScreenHeight: number;
let screenCheckedThisTurn = false;

function invalidateIfScreenSizeChanged(): void {
if (screenCheckedThisTurn) {
return;
}
screenCheckedThisTurn = true;
queueMicrotask(() => (screenCheckedThisTurn = false));

const { widthPixels, heightPixels } = Screen.mainScreen;
if (widthPixels !== cachedScreenWidth || heightPixels !== cachedScreenHeight) {
cachedScreenWidth = widthPixels;
cachedScreenHeight = heightPixels;
invalidateMediaQueryCache();
}
}

function checkIfMediaQueryMatchesCached(mediaQueryString: string): boolean {
invalidateIfScreenSizeChanged();
let matches = cssQueryResults.get(mediaQueryString);
if (matches === undefined) {
matches = checkIfMediaQueryMatches(mediaQueryString);
cssQueryResults.set(mediaQueryString, matches);
}
return matches;
}

function invalidateMediaQueryCache(): void {
cssQueryResults.clear();
mediaQueryEpoch++;
}

function getMediaQueryEpoch(): number {
return mediaQueryEpoch;
}

function matchMedia(mediaQueryString: string): MediaQueryListImpl {
isMediaInitializationEnabled = true;
const mediaQueryList = new MediaQueryListImpl();
Expand Down Expand Up @@ -202,4 +245,4 @@ class MediaQueryListImpl extends Observable implements MediaQueryList {
}
}

export { matchMedia, MediaQueryListImpl as MediaQueryList, checkIfMediaQueryMatches };
export { matchMedia, MediaQueryListImpl as MediaQueryList, checkIfMediaQueryMatches, checkIfMediaQueryMatchesCached, invalidateMediaQueryCache, getMediaQueryEpoch };
6 changes: 3 additions & 3 deletions packages/core/ui/styling/css-selector.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { isNullOrUndefined } from '../../utils/types';
import { cleanupImportantFlags } from './css-utils';

import * as ReworkCSS from '../../css';
import { checkIfMediaQueryMatches } from '../../media-query-list';
import { checkIfMediaQueryMatchesCached } from '../../media-query-list';

/**
* An interface describing the shape of a type on which the selectors may apply.
Expand Down Expand Up @@ -1127,7 +1127,7 @@ export function matchMediaQueryString(mediaQueryString: string | string[], cache
return true;
}

const result = checkIfMediaQueryMatches(mediaQueryString);
const result = checkIfMediaQueryMatchesCached(mediaQueryString);
if (result) {
cachedQueries.push(mediaQueryString);
return result;
Expand All @@ -1144,7 +1144,7 @@ export function matchMediaQueryString(mediaQueryString: string | string[], cache
continue;
}

if (!checkIfMediaQueryMatches(mq)) {
if (!checkIfMediaQueryMatchesCached(mq)) {
return false;
}

Expand Down
Loading

Back | FazBrowse Home | New Git URL