Cache local storage to improve performance
This commit is contained in:
parent
9fb009c8f7
commit
329a030f28
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "minesweeper",
|
||||
"version": "0.81.1",
|
||||
"version": "0.81.2",
|
||||
"description": "Just Minesweeper!",
|
||||
"author": "Felix W. Dekker",
|
||||
"browser": "dist/bundle.js",
|
||||
|
|
|
@ -8,6 +8,7 @@ import {BasicIconFont, Display, ForkAwesomeFont} from "./Display";
|
|||
import {Field} from "./Field";
|
||||
import {Solver} from "./Solver";
|
||||
import {LocalStatistics} from "./Statistics";
|
||||
import {Storage} from "./Storage";
|
||||
import {Overlay} from "./UI";
|
||||
|
||||
|
||||
|
@ -444,36 +445,14 @@ export class Game {
|
|||
* The player's preferences.
|
||||
*/
|
||||
export class Preferences {
|
||||
private static readonly storageKey = "/tools/minesweeper//preferences";
|
||||
|
||||
/**
|
||||
* Reads the object stored in local storage.
|
||||
*
|
||||
* @return the object stored in local storage, or an empty object if there is nothing in the local storage
|
||||
* @private
|
||||
*/
|
||||
private read(): { [key: string]: string } {
|
||||
return JSON.parse(localStorage.getItem(Preferences.storageKey) ?? "{}");
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the given object to local storage.
|
||||
*
|
||||
* @param statistics the object to write to local storage
|
||||
* @private
|
||||
*/
|
||||
private write(statistics: { [key: string]: string }): void {
|
||||
localStorage.setItem(Preferences.storageKey, JSON.stringify(statistics));
|
||||
}
|
||||
private readonly storage = new Storage("/tools/minesweeper//preferences");
|
||||
|
||||
|
||||
get marksEnabled(): boolean {
|
||||
return (this.read()["marksEnabled"] ?? "true") === "true";
|
||||
return this.storage.getBoolean("marksEnabled", true);
|
||||
}
|
||||
|
||||
set marksEnabled(value: boolean) {
|
||||
const preferences = this.read();
|
||||
preferences["marksEnabled"] = "" + value;
|
||||
this.write(preferences);
|
||||
this.storage.setBoolean("marksEnabled", value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import {formatTime} from "./Common";
|
||||
import {Storage} from "./Storage";
|
||||
|
||||
|
||||
/**
|
||||
|
@ -35,181 +36,132 @@ export interface Statistics {
|
|||
* Stores game statistics in the browser's localstorage.
|
||||
*/
|
||||
export class LocalStatistics implements Statistics {
|
||||
private static readonly storageKey = "/tools/minesweeper//statistics";
|
||||
private readonly storage = new Storage("/tools/minesweeper//statistics");
|
||||
|
||||
/**
|
||||
* Reads the object stored in local storage.
|
||||
*
|
||||
* @return the object stored in local storage, or an empty object if there is nothing in the local storage
|
||||
* @private
|
||||
*/
|
||||
private read(): { [key: string]: string } {
|
||||
return JSON.parse(localStorage.getItem(LocalStatistics.storageKey) ?? "{}");
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the given object to local storage.
|
||||
*
|
||||
* @param statistics the object to write to local storage
|
||||
* @private
|
||||
*/
|
||||
private write(statistics: { [key: string]: string }): void {
|
||||
localStorage.setItem(LocalStatistics.storageKey, JSON.stringify(statistics));
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
localStorage.removeItem(LocalStatistics.storageKey);
|
||||
this.storage.clear();
|
||||
}
|
||||
|
||||
|
||||
get actionsUndone(): number {
|
||||
return +(this.read()["actionsUndone"] ?? 0);
|
||||
return this.storage.getNumber("actionsUndone", 0);
|
||||
}
|
||||
|
||||
set actionsUndone(value: number) {
|
||||
const statistics = this.read();
|
||||
statistics["actionsUndone"] = "" + value;
|
||||
this.write(statistics);
|
||||
this.storage.setNumber("actionsUndone", value);
|
||||
}
|
||||
|
||||
get actionsRedone(): number {
|
||||
return +(this.read()["actionsRedone"] ?? 0);
|
||||
return this.storage.getNumber("actionsRedone", 0);
|
||||
}
|
||||
|
||||
set actionsRedone(value: number) {
|
||||
const statistics = this.read();
|
||||
statistics["actionsRedone"] = "" + value;
|
||||
this.write(statistics);
|
||||
this.storage.setNumber("actionsRedone", value);
|
||||
}
|
||||
|
||||
get lossesUndone(): number {
|
||||
return +(this.read()["lossesUndone"] ?? 0);
|
||||
return this.storage.getNumber("lossesUndone", 0);
|
||||
}
|
||||
|
||||
set lossesUndone(value: number) {
|
||||
const statistics = this.read();
|
||||
statistics["lossesUndone"] = "" + value;
|
||||
this.write(statistics);
|
||||
this.storage.setNumber("lossesUndone", value);
|
||||
}
|
||||
|
||||
get timeSpent(): number {
|
||||
return +(this.read()["timeSpent"] ?? 0);
|
||||
return this.storage.getNumber("timeSpent", 0);
|
||||
}
|
||||
|
||||
set timeSpent(value: number) {
|
||||
const statistics = this.read();
|
||||
statistics["timeSpent"] = "" + value;
|
||||
this.write(statistics);
|
||||
this.storage.setNumber("timeSpent", value);
|
||||
}
|
||||
|
||||
get gamesStarted(): number {
|
||||
return +(this.read()["gamesStarted"] ?? 0);
|
||||
return this.storage.getNumber("gamesStarted", 0);
|
||||
}
|
||||
|
||||
set gamesStarted(value: number) {
|
||||
const statistics = this.read();
|
||||
statistics["gamesStarted"] = "" + value;
|
||||
this.write(statistics);
|
||||
this.storage.setNumber("gamesStarted", value);
|
||||
}
|
||||
|
||||
get gamesLost(): number {
|
||||
return +(this.read()["gamesLost"] ?? 0);
|
||||
return this.storage.getNumber("gamesLost", 0);
|
||||
}
|
||||
|
||||
set gamesLost(value: number) {
|
||||
const statistics = this.read();
|
||||
statistics["gamesLost"] = "" + value;
|
||||
this.write(statistics);
|
||||
this.storage.setNumber("gamesLost", value);
|
||||
}
|
||||
|
||||
get gamesWon(): number {
|
||||
return +(this.read()["gamesWon"] ?? 0);
|
||||
return this.storage.getNumber("gamesWon", 0);
|
||||
}
|
||||
|
||||
set gamesWon(value: number) {
|
||||
const statistics = this.read();
|
||||
statistics["gamesWon"] = "" + value;
|
||||
this.write(statistics);
|
||||
this.storage.setNumber("gamesWon", value);
|
||||
}
|
||||
|
||||
get gamesWonWithoutLosing(): number {
|
||||
return +(this.read()["gamesWonWithoutLosing"] ?? 0);
|
||||
return this.storage.getNumber("gamesWonWithoutLosing", 0);
|
||||
}
|
||||
|
||||
set gamesWonWithoutLosing(value: number) {
|
||||
const statistics = this.read();
|
||||
statistics["gamesWonWithoutLosing"] = "" + value;
|
||||
this.write(statistics);
|
||||
this.storage.setNumber("gamesWonWithoutLosing", value);
|
||||
}
|
||||
|
||||
get squaresChorded(): number {
|
||||
return +(this.read()["squaresChorded"] ?? 0);
|
||||
return this.storage.getNumber("squaresChorded", 0);
|
||||
}
|
||||
|
||||
set squaresChorded(value: number) {
|
||||
const statistics = this.read();
|
||||
statistics["squaresChorded"] = "" + value;
|
||||
this.write(statistics);
|
||||
this.storage.setNumber("squaresChorded", value);
|
||||
}
|
||||
|
||||
get squaresChordedLeadingToLoss(): number {
|
||||
return +(this.read()["squaresChordedLeadingToLoss"] ?? 0);
|
||||
return this.storage.getNumber("squaresChordedLeadingToLoss", 0);
|
||||
}
|
||||
|
||||
set squaresChordedLeadingToLoss(value: number) {
|
||||
const statistics = this.read();
|
||||
statistics["squaresChordedLeadingToLoss"] = "" + value;
|
||||
this.write(statistics);
|
||||
this.storage.setNumber("squaresChordedLeadingToLoss", value);
|
||||
}
|
||||
|
||||
get squaresFlagged(): number {
|
||||
return +(this.read()["squaresFlagged"] ?? 0);
|
||||
return this.storage.getNumber("squaresFlagged", 0);
|
||||
}
|
||||
|
||||
set squaresFlagged(value: number) {
|
||||
const statistics = this.read();
|
||||
statistics["squaresFlagged"] = "" + value;
|
||||
this.write(statistics);
|
||||
this.storage.setNumber("squaresFlagged", value);
|
||||
}
|
||||
|
||||
get squaresMarked(): number {
|
||||
return +(this.read()["squaresMarked"] ?? 0);
|
||||
return this.storage.getNumber("squaresMarked", 0);
|
||||
}
|
||||
|
||||
set squaresMarked(value: number) {
|
||||
const statistics = this.read();
|
||||
statistics["squaresMarked"] = "" + value;
|
||||
this.write(statistics);
|
||||
this.storage.setNumber("squaresMarked", value);
|
||||
}
|
||||
|
||||
get squaresUncovered(): number {
|
||||
return +(this.read()["squaresUncovered"] ?? 0);
|
||||
return this.storage.getNumber("squaresUncovered", 0);
|
||||
}
|
||||
|
||||
set squaresUncovered(value: number) {
|
||||
const statistics = this.read();
|
||||
statistics["squaresUncovered"] = "" + value;
|
||||
this.write(statistics);
|
||||
this.storage.setNumber("squaresUncovered", value);
|
||||
}
|
||||
|
||||
get hintsRequested(): number {
|
||||
return +(this.read()["hintsRequested"] ?? 0);
|
||||
return this.storage.getNumber("hintsRequested", 0);
|
||||
}
|
||||
|
||||
set hintsRequested(value: number) {
|
||||
const statistics = this.read();
|
||||
statistics["hintsRequested"] = "" + value;
|
||||
this.write(statistics);
|
||||
this.storage.setNumber("hintsRequested", value);
|
||||
}
|
||||
|
||||
get solverUsages(): number {
|
||||
return +(this.read()["solverUsages"] ?? 0);
|
||||
return this.storage.getNumber("solverUsages", 0);
|
||||
}
|
||||
|
||||
set solverUsages(value: number) {
|
||||
const statistics = this.read();
|
||||
statistics["solverUsages"] = "" + value;
|
||||
this.write(statistics);
|
||||
this.storage.setNumber("solverUsages", value);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/**
|
||||
* Persistent storage, in particular `localStorage`.
|
||||
*/
|
||||
export class Storage {
|
||||
private readonly key: string;
|
||||
private _cache: { [key: string]: string } | null = null;
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new persistent storage item under the given key.
|
||||
*
|
||||
* @param key the unique identifier to store the data under
|
||||
*/
|
||||
constructor(key: string) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads the object stored in local storage.
|
||||
*
|
||||
* @return the object stored in local storage, or an empty object if there is nothing in the local storage
|
||||
* @private
|
||||
*/
|
||||
private read(): { [key: string]: string } {
|
||||
if (this._cache === null)
|
||||
this._cache = JSON.parse(localStorage.getItem(this.key) ?? "{}");
|
||||
|
||||
return this._cache!;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the given object to local storage.
|
||||
*
|
||||
* @param item the object to write to local storage
|
||||
* @private
|
||||
*/
|
||||
private write(item: { [key: string]: string }): void {
|
||||
this._cache = item;
|
||||
localStorage.setItem(this.key, JSON.stringify(item));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes the data from storage.
|
||||
*/
|
||||
clear(): void {
|
||||
this._cache = null;
|
||||
localStorage.removeItem(this.key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a boolean from storage.
|
||||
*
|
||||
* @param name the name of the boolean to retrieve
|
||||
* @param def the value to return if no boolean is stored with the given name
|
||||
* @protected
|
||||
*/
|
||||
getBoolean(name: string, def: boolean = false): boolean {
|
||||
return (this.read()[name] ?? `${def}`) === "true";
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a boolean.
|
||||
*
|
||||
* @param name the name of the boolean to store
|
||||
* @param value the boolean to store under the given name
|
||||
* @protected
|
||||
*/
|
||||
setBoolean(name: string, value: boolean): void {
|
||||
const item = this.read();
|
||||
item[name] = "" + value;
|
||||
this.write(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a number from storage.
|
||||
*
|
||||
* @param name the name of the number to retrieve
|
||||
* @param def the value to return if no number is stored with the given name
|
||||
* @protected
|
||||
*/
|
||||
getNumber(name: string, def: number = 0): number {
|
||||
return +(this.read()[name] ?? def);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a number.
|
||||
*
|
||||
* @param name the name of the number to store
|
||||
* @param value the number to store under the given name
|
||||
* @protected
|
||||
*/
|
||||
setNumber(name: string, value: number): void {
|
||||
const item = this.read();
|
||||
item[name] = "" + value;
|
||||
this.write(item);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue