Skip to content

Caching and Refresh

A user may open the same chart several times or change reports while an earlier request is still loading. Read policy controls whether the browser can reuse a result; cancellation and cleanup prevent obsolete work from replacing the current chart.

Try it: choose Measure duplicate requests, then Commit new Pivot filter revision, and measure again. A reusable result avoids a provider read; a new revision needs new data. This is separate from a cache inside your backend. Start with shared server-data loading if these terms are new.

Interactive example

Shared Query and request lifecycle

Repeat semantic chart reads and inspect Query-backed provider call counts; no custom server-response cache is used.

The example loads when visible.

Both complete chart reads and requested windows use built-in browser caching. Configure dataProvider.query; you do not need to install or create another cache client. Pivot Charts validates responses before reusing them. The displayed chart remains available while a newer result loads.

SettingMeaning
request.chart.queryAnalytical instructions: slice, filters, sort, ranking and selected measures. Requires the provider’s analytical-query capability.
dataProvider.queryRead policy: freshness, retention, retries and optional shared source. Does not change the aggregation contract.
import type { PivotChartDataProvider } from '@revolist/pivot';
const dataProvider: PivotChartDataProvider = {
query: { staleTime: 30_000, gcTime: 300_000, retry: 2 },
async load(request, { signal }) {
const response = await fetch('/api/pivot/chart-data', {
method: 'POST', signal,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(request),
});
if (!response.ok) throw new Error(`Chart data failed: ${response.status}`);
return response.json();
},
};
  • staleTime sets how long a successful response may be reused. Use 0 to request a fresh frame on each new read with the default mount/refetch policy.
  • gcTime sets inactive cache retention; it does not make a response fresh.
  • query: false bypasses the Query cache and native automatic read policy. Revisiting a drill scope then calls the provider again.
  • retry applies to failed reads, including a POST used to execute an analytical read. It does not retry report saves or other writes.

Every provider call receives an AbortSignal. Abort underlying HTTP, query, and decoding work when possible. Root loads, linked refreshes, and drill transitions carry monotonically increasing revisions. The plugin ignores a completion that is no longer current even if the provider did not stop after abort.

During drill, the last successful frame remains rendered. During a linked refresh, the UI exposes a loading state and commits the replacement only after data validation and renderer update succeed.

A complete frame is loaded as a promise. Its Query observer is released after settlement, so setting refetchInterval does not create an always-running polling loop for an idle chart. Acquire another frame through the chart lifecycle:

await charts.refreshChart(chart.id);

Refresh re-enters the provider read path; the configured freshness policy still applies. Use staleTime: 0 when each read must reach the backend. Accepted current-frame data remains displayed between reads; that display state is not a second remote response cache.

Each owner gets a private cache by default. Share a DataQueryScope only between readers of the same dataset, schema, tenant and authorization scope; never use credentials as scope identifiers. See shared Query configuration.

OwnerOptional configurationLifetime and refresh
PivotChartDataProviderquery?: PivotChartQueryOptions | falseComplete and viewport responses have separate keys and validators. A provider read releases its observer on settlement; Pivot Charts releases pending reads when its owner is destroyed.

PivotChartQueryOptions omits product reconciliation/snapshot callbacks; domain validation stays in Pivot. Complete/viewport keys retain analytical identity and pass completeness, scope, query-echo, matrix and viewport validation before caching. Promise reads release their observer on settlement and do not continue background polling; refresh the chart explicitly to acquire another frame. Cancelling one caller leaves peer subscriptions active; cancelling the last subscriber aborts transport and prevents late results from committing.

See Pivot shared read ownership for provider identity, correlation, cancellation and disposal.

import { createDataQueryContext } from '@revolist/pivot';
const context = createDataQueryContext();
const source = context.source({
sourceId: 'sales-charts', schemaId: 'v1',
tenantId: 'tenant-1', authorizationScope: 'sales-reader',
});
// Supply source through each equivalent provider's query configuration.
// dataProvider.query = { source, staleTime: 30_000 };
// After destroying all consuming chart/Pivot owners:
context.dispose();

Do not share a scope across tenants or authorization identities. Destroy the consuming owners before disposing an application-owned context. Replacing the provider or destroying its owner releases pending reads and observers; one cancelled reader does not abort a transport still needed by a peer.

Client-engine Pivot projections may memoize normalized datasets and drill results to avoid repeating local analytical work. The gallery may reuse decorative SVG previews. These local computation/rendering caches do not store server responses or override dataProvider.query. See Renderer Choices.

The live counter in this article uses Query for reuse. Choose Measure duplicate requests to compare provider calls, then advance the committed Pivot revision to see a new semantic request.

See your first chart, data and measures and the API reference.