npm package: @rasir/page-storage
Description: 使用indexdb对当前页面数据缓存
Author: Rasir
Latest version: 0.0.5

# ra-page-storage

[Chinese](./README.md)

#### Introduction

`page-storage` utilizes `sessionStorage` and `indexdb` to cache data for the current tab, and the cached data is invalidated when the page is closed.

#### How It Works

1、`page-storage` caches the current window's `uuid` using `sessionStorage`, and reads the `uuid` from `sessionStorage` when the page is refreshed. If it exists, cached data will be read; if not, a new `uuid` will be generated.

2、Built on top of `indexdb`, `page-storage` is easy to use, supporting operations such as data caching, deletion, updates, and queries. The `key` stored in `indexdb` is each window's `uuid`, which also has an expiration time (`expiredTime`) tagged to its data by default 10s (customizable).

3、Using `web worker`, `page-storage` polls data in `indexdb` for renewal at half of the expired time (can be customized), default is 5s.

4、`page-storage` also uses `@rasir/chain-promise-call`, making all operations work in chain calls to ensure ongoing indexdb operations.

5、All APIs of `page-storage` support promise operations.

#### Precautions

1、Browser compatibility: compatible with any browser versions that support Promise.

2、Depends on `@rasir/chain-promise-call`.

3、This project uses `"core-js": "^3.32.1"`. If there are compatibility issues during use, please check the core-js version.

4、Chain calls mentioned here don't follow jQuery-style chaining but put all chainable APIs into a stack, executing subsequent functions only after an asynchronous function completes ensuring orderly storage of operation data in `indexdb`.

#### Quick Start

Install via NPM:

`npm i @rasir/page-storage -S`

#### Usage

1.Direct reference via HTML:

```js
<script src="xxx/xxx/page-storage-0.0.1.min.js"></script>
<script>
    const storage = new PageStorage({
    dbName: "demo_db",
    sessionWindowKey: "DEMO_KEY",
    });
    storage.chainSavePageStorage({ a: 1, b: 2 });
    storage.chainGetPageStorage().then((data) => {
    console.log(data);
    });
</script>
```

2.Use with npm:

```js
import PageStorage from "@rasir/page-storage";
const storage = new PageStorage({
  dbName: "demo_db",
  sessionWindowKey: "DEMO_KEY",
});
storage.chainSavePageStorage({ a: 1, b: 2 });
storage.chainGetPageStorage().then((data) => {
  console.log(data);
});
```

#### Parameter Description

```js
interface IPageStorage {
  noWindowName?: boolean; // 是否不使用窗口名称作为窗口特征码，默认 false
  windowName?: string; // 当前窗口的特征码，默认 PAGE_STORAGE
  windowId?: string; // The uuid of the current window
  expiredTime?: number; // Expiration time, in seconds, default is 10s
  dbName: string; // The storeName in indexdb, must be provided
  sessionWindowKey: string; // The key for saving windowId in sessionStorage, must be provided
}
```

#### APIs

| API                      | Description                                                                                                                                      | Parameter Type                                                                           |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------- |
| `getPageStorage`         | Get Data From Current Window                                                                                                                     | `(): Promise<T \| undefined>`                                                            |
| `savePageStorage`        | Save Data To Current Window                                                                                                                      | `(data: T): Promise<boolean> `                                                           |
| `updatePageStorage`      | Directly Amend Data Of Current Window                                                                                                            | `(callback: (data?: T) => T \| Promise<T>): Promise<boolean>;`                           |
| `removePageStorage`      | Remove Data From Current Window                                                                                                                  | `(): Promise<boolean>;`                                                                  |
| `dispose`                | Stop Renewing Data                                                                                                                               | `(): Promise<boolean>;`                                                                  |
| `chainGetPageStorage`    | Chain-Call To Get Data From Current Window                                                                                                       | `(): Promise<T \| undefined> `                                                           |
| `chainSavePageStorage`   | Chain-Call To Save Data To The Current Window                                                                                                    | `(data: T): Promise<boolean> `                                                           |
| `chainUpdatePageStorage` | Chain-Call to Directly Amend the Data of the Current Window                                                                                      | `(callback: (data?: T) => T \| Promise<T>): Promise<boolean>;`                           |
| `chainRemovePageStorage` | Chain Call to Delete the data from the Current Window                                                                                            | (): Promise;                                                                             |
| `chainDispose`           | Chain-call for Stopping to renew data                                                                                                            | `(): Promise<boolean>;`                                                                  |
| `chainPromiseCall`       | Function for chaining. You can use `chainPromiseCall.onStatusChange` and `chainPromiseCall.offStatusChange` to listen to instance state changes. | See [@rasir/chain-promise-call](https://gitee.com/rasir/chain-promise-call) for details. |

#### Problem and Solutions

- Problem: When using `window.open` to open a new page from an existing one, the data in `sessionStorage` is copied to the new page. This causes our design, which uses `sessionWindowKey` for individual storage on each page, to fail.
- Solutions:
  1. Use `window.name` to label the current page. Since refreshing the page does not reset `window.name`, I added a property named `windowName` in the constructor for checking whether the current page is new. If a new page does not carry a characteristic code with `windowName`, then clear the `sessionWindowKey` in `sessionStorage`, and set a name with a characteristic code for `window.name`. Of course, if you do not want my approach with `window.name` interfering with your design, you can set an attribute called `noWindowName`, so that you need to ensure `sessionStorage` uniqueness by yourself.
  2. Abandon using native function of `window.open`. You can use <a> tag for redirection or simulate click redirection on <a> tag as follows:
  ```js
  let link = document.createElement("a");
  link.href = "http://example.com";
  link.target = "_blank";
  link.click();
  ```