Persister
A Persister
object lets you save and load Store
data to and from different locations, or underlying storage types.
This is useful for preserving Store
or MergeableStore
data between browser sessions or reloads, saving or loading browser state to or from a server, or saving Store
data to disk in a environment with filesystem access.
Creating a Persister
depends on the choice of underlying storage where the data is to be stored. Options include the createSessionPersister
function, the createLocalPersister
function, the createRemotePersister
function, and the createFilePersister
function, as just simple examples. The createCustomPersister
function can also be used to easily create a fully customized way to save and load Store
data.
Using the values of the Persists
enum, the generic parameter to the Persister
indicates whether it can handle a regular Store
, a MergeableStore
, or either. Consult the table in the overall persisters
module documentation to see current support for each. The different levels of support are also described for each of the types of Persister
themselves.
A Persister
lets you explicit save or load data, with the save
method and the load
method respectively. These methods are both asynchronous (since the underlying data storage may also be) and return promises. As a result you should use the await
keyword to call them in a way that guarantees subsequent execution order.
When you don't want to deal with explicit persistence operations, a Persister
object also provides automatic saving and loading. Automatic saving listens for changes to the Store
and persists the data immediately. Automatic loading listens (or polls) for changes to the persisted data and reflects those changes in the Store
.
You can start automatic saving or loading with the startAutoSave
method and startAutoLoad
method. Both are asynchronous since they will do an immediate save and load before starting to listen for subsequent changes. You can stop the behavior with the stopAutoSave
method and stopAutoLoad
method (which are synchronous).
You may often want to have both automatic saving and loading of a Store
so that changes are constantly synchronized (allowing basic state preservation between browser tabs, for example). The framework has some basic provisions to prevent race conditions - for example it will not attempt to save data if it is currently loading it and vice-versa - and will sequentially schedule
methods that could cause race conditions.
That said, be aware that you should always comprehensively test your persistence strategy to understand the opportunity for data loss (in the case of trying to save data to a server under poor network conditions, for example).
To help debug such issues, since v4.0.4, the create methods for all Persister
objects take an optional onIgnoredError
argument. This is a handler for the errors that the Persister
would otherwise ignore when trying to save or load data (such as when handling corrupted stored data). It's recommended you use this for debugging persistence issues, but only in a development environment. Database-based Persister
objects also take an optional onSqlCommand
argument for logging commands and queries made to the underlying database.
Examples
This example creates a Store
, persists it to the browser's session storage as a JSON string, changes the persisted data, updates the Store
from it, and finally destroys the Persister
again.
import {createSessionPersister} from 'tinybase/persisters/persister-browser';
import {createStore} from 'tinybase';
const store = createStore().setTables({pets: {fido: {species: 'dog'}}});
const persister = createSessionPersister(store, 'pets');
await persister.save();
console.log(sessionStorage.getItem('pets'));
// -> '[{"pets":{"fido":{"species":"dog"}}},{}]'
sessionStorage.setItem('pets', '[{"pets":{"toto":{"species":"dog"}}},{}]');
await persister.load();
console.log(store.getTables());
// -> {pets: {toto: {species: 'dog'}}}
persister.destroy();
sessionStorage.clear();
This example creates a Store
, and automatically saves and loads it to the browser's session storage as a JSON string. Changes
to the Store
data, or the persisted data (implicitly firing a StorageEvent), are reflected accordingly.
import {createSessionPersister} from 'tinybase/persisters/persister-browser';
import {createStore} from 'tinybase';
const store = createStore();
const persister = createSessionPersister(store, 'pets');
await persister.startAutoLoad([{pets: {fido: {species: 'dog'}}}, {}]);
await persister.startAutoSave();
store.setTables({pets: {felix: {species: 'cat'}}});
// ...
console.log(sessionStorage.getItem('pets'));
// -> '[{"pets":{"felix":{"species":"cat"}}},{}]'
// In another browser tab:
sessionStorage.setItem('pets', '[{"pets":{"toto":{"species":"dog"}}},{}]');
// -> StorageEvent('storage', {storageArea: sessionStorage, key: 'pets'})
// ...
console.log(store.getTables());
// -> {pets: {toto: {species: 'dog'}}}
persister.destroy();
sessionStorage.clear();
Since
v1.0.0
Getter methods
This is the collection of getter methods within the Persister
interface. There is only one method, getStore
.
Listener methods
This is the collection of listener methods within the Persister
interface. There are only two listener methods, addStatusListener
and delListener
.
Lifecycle methods
This is the collection of lifecycle methods within the Persister
interface. There are only three lifecycle methods, destroy
, getStatus
, and schedule
.
Load methods
This is the collection of load methods within the Persister
interface. There are 4 load methods in total.
Save methods
This is the collection of save methods within the Persister
interface. There are 4 save methods in total.
Development methods
This is the collection of development methods within the Persister
interface. There is only one method, getStats
.