Skip to content

Commit 20eba92

Browse files
committed
⚡️ 性能优化
1 parent c299df0 commit 20eba92

28 files changed

+669
-299
lines changed

src/app/cache.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export interface CacheStorage {
22
get(key: string): Promise<any>;
33
set(key: string, value: any): Promise<void>;
4+
batchSet(data: { [key: string]: any }): Promise<void>;
45
has(key: string): Promise<boolean>;
56
del(key: string): Promise<void>;
67
list(): Promise<string[]>;
@@ -28,6 +29,14 @@ export class ExtCache implements CacheStorage {
2829
});
2930
}
3031

32+
batchSet(data: { [key: string]: any }): Promise<void> {
33+
return new Promise((resolve) => {
34+
chrome.storage.session.set(data, () => {
35+
resolve();
36+
});
37+
});
38+
}
39+
3140
has(key: string): Promise<boolean> {
3241
return new Promise((resolve) => {
3342
chrome.storage.session.get(key, (value) => {
@@ -123,6 +132,10 @@ export default class Cache {
123132
return this.storage.set(key, value);
124133
}
125134

135+
public batchSet(data: { [key: string]: any }): Promise<void> {
136+
return this.storage.batchSet(data);
137+
}
138+
126139
public has(key: string): Promise<boolean> {
127140
return this.storage.has(key);
128141
}

src/app/repo/repo.ts

Lines changed: 106 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,53 @@
1+
// 加载全局缓存
2+
3+
let loadCachePromise: Promise<any> | undefined = undefined;
4+
let cache: { [key: string]: any } | undefined = undefined;
5+
6+
// 加载数据到缓存
7+
function loadCache(): Promise<any> {
8+
if (cache) {
9+
return Promise.resolve(cache);
10+
}
11+
if (loadCachePromise) {
12+
return loadCachePromise;
13+
}
14+
loadCachePromise = new Promise((resolve) => {
15+
chrome.storage.local.get((result) => {
16+
cache = result;
17+
resolve(cache);
18+
});
19+
});
20+
return loadCachePromise;
21+
}
22+
23+
function saveCache(key: string, value: any) {
24+
loadCache().then(() => {
25+
cache![key] = value;
26+
});
27+
return chrome.storage.local.set({ [key]: value });
28+
}
29+
30+
function deleteCache(key: string) {
31+
loadCache().then(() => {
32+
delete cache![key];
33+
});
34+
return chrome.storage.local.remove(key);
35+
}
36+
137
export abstract class Repo<T> {
38+
// 开启缓存,不重复加载数据
39+
useCache: boolean = false;
40+
241
constructor(protected prefix: string) {
342
if (!prefix.endsWith(":")) {
443
this.prefix += ":";
544
}
645
}
746

47+
enableCache() {
48+
this.useCache = true;
49+
}
50+
851
protected joinKey(key: string) {
952
return this.prefix + key;
1053
}
@@ -14,13 +57,26 @@ export abstract class Repo<T> {
1457
const data = {
1558
[this.joinKey(key)]: val,
1659
};
60+
if (this.useCache) {
61+
return saveCache(this.joinKey(key), val).then(() => {
62+
return resolve(val);
63+
});
64+
}
1765
chrome.storage.local.set(data, () => {
1866
resolve(val);
1967
});
2068
});
2169
}
2270

2371
public get(key: string): Promise<T | undefined> {
72+
if (this.useCache) {
73+
return loadCache().then((cache) => {
74+
if (cache[this.joinKey(key)]) {
75+
return Object.assign({}, cache[this.joinKey(key)]);
76+
}
77+
return cache[this.joinKey(key)];
78+
});
79+
}
2480
return new Promise((resolve) => {
2581
key = this.joinKey(key);
2682
chrome.storage.local.get(key, (result) => {
@@ -29,34 +85,51 @@ export abstract class Repo<T> {
2985
});
3086
}
3187

32-
public find(filters?: (key: string, value: T) => boolean): Promise<T[]> {
33-
return new Promise((resolve) => {
34-
chrome.storage.local.get((result) => {
35-
const ret = [];
36-
for (const key in result) {
37-
if (key.startsWith(this.prefix) && (!filters || filters(key, result[key]))) {
38-
ret.push(result[key]);
39-
}
88+
private filter(data: { [key: string]: T }, filters?: (key: string, value: T) => boolean): T[] {
89+
const ret: T[] = [];
90+
for (const key in data) {
91+
if (key.startsWith(this.prefix)) {
92+
if (!filters || filters(key, data[key])) {
93+
ret.push(data[key]);
4094
}
41-
resolve(ret);
42-
});
43-
});
95+
}
96+
}
97+
return ret;
4498
}
4599

46-
findOne(filters?: (key: string, value: T) => boolean): Promise<T | undefined> {
47-
return new Promise((resolve) => {
48-
chrome.storage.local.get((result) => {
49-
for (const key in result) {
50-
if (key.startsWith(this.prefix) && (!filters || filters(key, result[key]))) {
51-
return resolve(result[key]);
100+
public async find(filters?: (key: string, value: T) => boolean): Promise<T[]> {
101+
if (this.useCache) {
102+
return loadCache().then((cache) => {
103+
return this.filter(cache, filters).map((item) => {
104+
if (item) {
105+
return Object.assign({}, item);
52106
}
53-
}
54-
resolve(undefined);
107+
return item;
108+
});
55109
});
56-
});
110+
}
111+
const loadData = () => {
112+
return new Promise<T[]>((resolve) => {
113+
chrome.storage.local.get((result) => {
114+
resolve(this.filter(result, filters));
115+
});
116+
});
117+
};
118+
return loadData();
119+
}
120+
121+
async findOne(filters?: (key: string, value: T) => boolean): Promise<T | undefined> {
122+
const list = await this.find(filters);
123+
if (list.length > 0) {
124+
return list[0];
125+
}
126+
return undefined;
57127
}
58128

59129
public delete(key: string) {
130+
if (this.useCache) {
131+
return deleteCache(this.joinKey(key));
132+
}
60133
return new Promise<void>((resolve) => {
61134
chrome.storage.local.remove(this.joinKey(key), () => {
62135
resolve();
@@ -65,6 +138,18 @@ export abstract class Repo<T> {
65138
}
66139

67140
update(key: string, val: Partial<T>): Promise<T | false> {
141+
if (this.useCache) {
142+
return loadCache().then((cache) => {
143+
const data = cache[this.joinKey(key)];
144+
if (data) {
145+
Object.assign(data, val);
146+
return saveCache(this.joinKey(key), data).then(() => {
147+
return data;
148+
});
149+
}
150+
return false;
151+
});
152+
}
68153
return new Promise((resolve) => {
69154
this.get(key).then((result) => {
70155
if (result) {
@@ -80,16 +165,6 @@ export abstract class Repo<T> {
80165
}
81166

82167
all(): Promise<T[]> {
83-
return new Promise((resolve) => {
84-
chrome.storage.local.get((result) => {
85-
const ret = [];
86-
for (const key in result) {
87-
if (key.startsWith(this.prefix)) {
88-
ret.push(result[key]);
89-
}
90-
}
91-
resolve(ret);
92-
});
93-
});
168+
return this.find();
94169
}
95170
}

src/app/repo/scripts.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@ export class ScriptDAO extends Repo<Script> {
8787
super("script");
8888
}
8989

90+
enableCache(): void {
91+
super.enableCache();
92+
this.scriptCodeDAO.enableCache();
93+
}
94+
9095
public save(val: Script) {
9196
return super._save(val.uuid, val);
9297
}

src/app/service/content/gm_api.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,10 @@ export default class GMApi {
6060

6161
valueChangeListener = new Map<number, { name: string; listener: GMTypes.ValueChangeListener }>();
6262

63-
constructor(private prefix: string, private message: Message) {}
63+
constructor(
64+
private prefix: string,
65+
private message: Message
66+
) {}
6467

6568
// 单次回调使用
6669
public sendMessage(api: string, params: any[]) {
@@ -777,6 +780,18 @@ export default class GMApi {
777780
this.sendMessage("GM_setClipboard", [data, info]);
778781
}
779782

783+
@GMContext.API()
784+
GM_getResourceText(name: string): string | undefined {
785+
if (!this.scriptRes.resource) {
786+
return undefined;
787+
}
788+
const r = this.scriptRes.resource[name];
789+
if (r) {
790+
return r.content;
791+
}
792+
return undefined;
793+
}
794+
780795
@GMContext.API()
781796
GM_getResourceURL(name: string, isBlobUrl?: boolean): string | undefined {
782797
if (!this.scriptRes.resource) {

src/app/service/queue.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ export function subscribeScriptInstall(
1010
return messageQueue.subscribe("installScript", callback);
1111
}
1212

13-
export function subscribeScriptDelete(messageQueue: MessageQueue, callback: (message: { uuid: string }) => void) {
13+
export function subscribeScriptDelete(
14+
messageQueue: MessageQueue,
15+
callback: (message: { uuid: string; script: Script }) => void
16+
) {
1417
return messageQueue.subscribe("deleteScript", callback);
1518
}
1619

src/app/service/service_worker/client.ts

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import Cache from "@App/app/cache";
1111
import CacheKey from "@App/app/cache_key";
1212
import { Subscribe } from "@App/app/repo/subscribe";
1313
import { Permission } from "@App/app/repo/permission";
14+
import { ResourceBackup } from "@App/pkg/backup/struct";
1415

1516
export class ServiceWorkerClient extends Client {
1617
constructor(msg: MessageSend) {
@@ -27,6 +28,11 @@ export class ScriptClient extends Client {
2728
super(msg, "serviceWorker/script");
2829
}
2930

31+
// 脚本数据量大的时候,options页要读取全部的数据,可能会导致options页卡顿,直接调用serviceWorker的接口从内存中读取数据
32+
getAllScripts(): Promise<Script[]> {
33+
return this.do("getAllScripts");
34+
}
35+
3036
// 获取安装信息
3137
getInstallInfo(uuid: string) {
3238
return this.do("getInstallInfo", uuid);
@@ -73,6 +79,10 @@ export class ScriptClient extends Client {
7379
requestCheckUpdate(uuid: string) {
7480
return this.do("requestCheckUpdate", uuid);
7581
}
82+
83+
sortScript(active: string, over: string) {
84+
return this.do("sortScript", { active, over });
85+
}
7686
}
7787

7888
export class ResourceClient extends Client {
@@ -101,6 +111,10 @@ export class ValueClient extends Client {
101111
setScriptValue(uuid: string, key: string, value: any) {
102112
return this.do("setScriptValue", { uuid, key, value });
103113
}
114+
115+
setScriptValues(uuid: string, values: { [key: string]: any }) {
116+
return this.do("setScriptValues", { uuid, values });
117+
}
104118
}
105119

106120
export class RuntimeClient extends Client {
@@ -203,9 +217,9 @@ export class SynchronizeClient extends Client {
203217
async openImportWindow(filename: string, file: File | Blob) {
204218
// 打开导入窗口,用cache实现数据交互
205219
const url = URL.createObjectURL(file);
206-
setTimeout(() => {
207-
URL.revokeObjectURL(url);
208-
}, 60 * 1000);
220+
// setTimeout(() => {
221+
// URL.revokeObjectURL(url);
222+
// }, 60 * 1000);
209223
const uuid = uuidv4();
210224
await Cache.getInstance().set(CacheKey.importFile(uuid), {
211225
filename: filename,
@@ -216,6 +230,15 @@ export class SynchronizeClient extends Client {
216230
url: `/src/import.html?uuid=${uuid}`,
217231
});
218232
}
233+
234+
importResources(
235+
uuid: string | undefined,
236+
requires: ResourceBackup[],
237+
resources: ResourceBackup[],
238+
requiresCss: ResourceBackup[]
239+
) {
240+
return this.do("importResources", { uuid, requires, resources, requiresCss });
241+
}
219242
}
220243

221244
export class SubscribeClient extends Client {

src/app/service/service_worker/index.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { SynchronizeService } from "./synchronize";
1111
import { SubscribeService } from "./subscribe";
1212
import { ExtServer, ExtVersion } from "@App/app/const";
1313
import { systemConfig } from "@App/pages/store/global";
14+
import { ScriptDAO } from "@App/app/repo/scripts";
1415

1516
export type InstallSource = "user" | "system" | "sync" | "subscribe" | "vscode";
1617

@@ -30,12 +31,15 @@ export default class ServiceWorkerManager {
3031
});
3132
this.sender.init();
3233

34+
const scriptDAO = new ScriptDAO();
35+
scriptDAO.enableCache();
36+
3337
const systemConfig = new SystemConfig(this.mq);
3438

3539
const resource = new ResourceService(this.api.group("resource"), this.mq);
3640
resource.init();
37-
const value = new ValueService(this.api.group("value"), this.sender);
38-
const script = new ScriptService(systemConfig, this.api.group("script"), this.mq, value, resource);
41+
const value = new ValueService(this.api.group("value"), this.sender, this.mq);
42+
const script = new ScriptService(systemConfig, this.api.group("script"), this.mq, value, resource, scriptDAO);
3943
script.init();
4044
const runtime = new RuntimeService(
4145
systemConfig,
@@ -44,10 +48,11 @@ export default class ServiceWorkerManager {
4448
this.mq,
4549
value,
4650
script,
47-
resource
51+
resource,
52+
scriptDAO
4853
);
4954
runtime.init();
50-
const popup = new PopupService(this.api.group("popup"), this.mq, runtime);
55+
const popup = new PopupService(this.api.group("popup"), this.mq, runtime, scriptDAO);
5156
popup.init();
5257
value.init(runtime, popup);
5358
const synchronize = new SynchronizeService(
@@ -94,7 +99,6 @@ export default class ServiceWorkerManager {
9499

95100
// 监听配置变化
96101
this.mq.subscribe("systemConfigChange", (msg) => {
97-
console.log("systemConfigChange", msg);
98102
switch (msg.key) {
99103
case "cloud_sync": {
100104
synchronize.cloudSyncConfigChange(msg.value);

0 commit comments

Comments
 (0)