@taicode/common-web 1.1.2 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,12 +2,18 @@ type ApiFunc<P extends unknown[], R = unknown> = (...args: P) => Promise<R>;
2
2
  export declare class CacheApi<P extends unknown[], R> {
3
3
  private func;
4
4
  private cache;
5
+ private lastArgs;
5
6
  private accessor pendingRequests;
6
7
  constructor(func: ApiFunc<P, R>);
7
8
  get loading(): boolean;
8
9
  get empty(): boolean;
9
10
  get value(): R | undefined;
10
- send(...args: P): Promise<R>;
11
+ call(...args: P): Promise<R>;
12
+ /**
13
+ * 使用最近一次的参数刷新数据
14
+ * @param force 强制刷新,清除缓存
15
+ */
16
+ refresh(force?: boolean): Promise<R>;
11
17
  }
12
18
  export {};
13
19
  //# sourceMappingURL=cache-api.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cache-api.d.ts","sourceRoot":"","sources":["../../source/cache-api/cache-api.ts"],"names":[],"mappings":"AAKA,KAAK,OAAO,CAAC,CAAC,SAAS,OAAO,EAAE,EAAE,CAAC,GAAG,OAAO,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAA;AAE3E,qBAAa,QAAQ,CAAC,CAAC,SAAS,OAAO,EAAE,EAAE,CAAC;IAO9B,OAAO,CAAC,IAAI;IANxB,OAAO,CAAC,KAAK,CAAqB;IAIlC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAI;gBAEhB,IAAI,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IAIvC,IACI,OAAO,IAAI,OAAO,CAErB;IAED,IACI,KAAK,IAAI,OAAO,CAEnB;IAED,IACI,KAAK,IAAI,CAAC,GAAG,SAAS,CAEzB;IAGK,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAmBnC"}
1
+ {"version":3,"file":"cache-api.d.ts","sourceRoot":"","sources":["../../source/cache-api/cache-api.ts"],"names":[],"mappings":"AAKA,KAAK,OAAO,CAAC,CAAC,SAAS,OAAO,EAAE,EAAE,CAAC,GAAG,OAAO,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAA;AAE3E,qBAAa,QAAQ,CAAC,CAAC,SAAS,OAAO,EAAE,EAAE,CAAC;IAU9B,OAAO,CAAC,IAAI;IATxB,OAAO,CAAC,KAAK,CAAqB;IAGlC,OAAO,CAAC,QAAQ,CAAe;IAI/B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAI;gBAEhB,IAAI,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IAIvC,IACI,OAAO,IAAI,OAAO,CAErB;IAED,IACI,KAAK,IAAI,OAAO,CAEnB;IAED,IACI,KAAK,IAAI,CAAC,GAAG,SAAS,CAEzB;IAGK,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAuBlC;;;OAGG;IAEG,OAAO,CAAC,KAAK,GAAE,OAAe,GAAG,OAAO,CAAC,CAAC,CAAC;CAalD"}
@@ -48,7 +48,7 @@ import { catchIt } from '@taicode/common-base';
48
48
  import { SideCache } from '../side-cache';
49
49
  let CacheApi = (() => {
50
50
  var _a, _CacheApi_pendingRequests_accessor_storage;
51
- var _b;
51
+ var _b, _c;
52
52
  let _instanceExtraInitializers = [];
53
53
  let _pendingRequests_decorators;
54
54
  let _pendingRequests_initializers = [];
@@ -56,7 +56,8 @@ let CacheApi = (() => {
56
56
  let _get_loading_decorators;
57
57
  let _get_empty_decorators;
58
58
  let _get_value_decorators;
59
- let _send_decorators;
59
+ let _call_decorators;
60
+ let _refresh_decorators;
60
61
  return _a = class CacheApi {
61
62
  // 记录当前正在进行的请求数量
62
63
  get pendingRequests() { return __classPrivateFieldGet(this, _CacheApi_pendingRequests_accessor_storage, "f"); }
@@ -67,7 +68,7 @@ let CacheApi = (() => {
67
68
  _CacheApi_pendingRequests_accessor_storage.set(this, __runInitializers(this, _pendingRequests_initializers, 0));
68
69
  __runInitializers(this, _pendingRequests_extraInitializers);
69
70
  this.func = func;
70
- this.send = this.send.bind(this);
71
+ this.call = this.call.bind(this);
71
72
  }
72
73
  get loading() {
73
74
  return this.pendingRequests > 0;
@@ -78,7 +79,9 @@ let CacheApi = (() => {
78
79
  get value() {
79
80
  return this.cache.value;
80
81
  }
81
- async send(...args) {
82
+ async call(...args) {
83
+ // 记录最近一次调用的参数
84
+ this.lastArgs = args;
82
85
  // 增加待处理请求计数
83
86
  this.pendingRequests++;
84
87
  const result = await catchIt(async () => {
@@ -93,6 +96,21 @@ let CacheApi = (() => {
93
96
  }
94
97
  return result.value;
95
98
  }
99
+ /**
100
+ * 使用最近一次的参数刷新数据
101
+ * @param force 强制刷新,清除缓存
102
+ */
103
+ async refresh(force = false) {
104
+ if (this.lastArgs === undefined) {
105
+ throw new Error('没有可用的参数来刷新数据,请先调用 call 方法');
106
+ }
107
+ if (force) {
108
+ // 强制刷新,先清除缓存
109
+ this.cache.clear(this.lastArgs);
110
+ }
111
+ // 重新调用最近一次的参数
112
+ return await this.call(...this.lastArgs);
113
+ }
96
114
  },
97
115
  _CacheApi_pendingRequests_accessor_storage = new WeakMap(),
98
116
  (() => {
@@ -101,12 +119,14 @@ let CacheApi = (() => {
101
119
  _get_loading_decorators = [computed];
102
120
  _get_empty_decorators = [computed];
103
121
  _get_value_decorators = [computed];
104
- _send_decorators = [(_b = action).bound.bind(_b)];
122
+ _call_decorators = [(_b = action).bound.bind(_b)];
123
+ _refresh_decorators = [(_c = action).bound.bind(_c)];
105
124
  __esDecorate(_a, null, _pendingRequests_decorators, { kind: "accessor", name: "pendingRequests", static: false, private: false, access: { has: obj => "pendingRequests" in obj, get: obj => obj.pendingRequests, set: (obj, value) => { obj.pendingRequests = value; } }, metadata: _metadata }, _pendingRequests_initializers, _pendingRequests_extraInitializers);
106
125
  __esDecorate(_a, null, _get_loading_decorators, { kind: "getter", name: "loading", static: false, private: false, access: { has: obj => "loading" in obj, get: obj => obj.loading }, metadata: _metadata }, null, _instanceExtraInitializers);
107
126
  __esDecorate(_a, null, _get_empty_decorators, { kind: "getter", name: "empty", static: false, private: false, access: { has: obj => "empty" in obj, get: obj => obj.empty }, metadata: _metadata }, null, _instanceExtraInitializers);
108
127
  __esDecorate(_a, null, _get_value_decorators, { kind: "getter", name: "value", static: false, private: false, access: { has: obj => "value" in obj, get: obj => obj.value }, metadata: _metadata }, null, _instanceExtraInitializers);
109
- __esDecorate(_a, null, _send_decorators, { kind: "method", name: "send", static: false, private: false, access: { has: obj => "send" in obj, get: obj => obj.send }, metadata: _metadata }, null, _instanceExtraInitializers);
128
+ __esDecorate(_a, null, _call_decorators, { kind: "method", name: "call", static: false, private: false, access: { has: obj => "call" in obj, get: obj => obj.call }, metadata: _metadata }, null, _instanceExtraInitializers);
129
+ __esDecorate(_a, null, _refresh_decorators, { kind: "method", name: "refresh", static: false, private: false, access: { has: obj => "refresh" in obj, get: obj => obj.refresh }, metadata: _metadata }, null, _instanceExtraInitializers);
110
130
  if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
111
131
  })(),
112
132
  _a;
@@ -25,7 +25,7 @@ describe('CacheApi', () => {
25
25
  expect(cacheApi.value).toBeUndefined();
26
26
  });
27
27
  it('应该正确绑定 send 方法', () => {
28
- const { send } = cacheApi;
28
+ const { call: send } = cacheApi;
29
29
  expect(typeof send).toBe('function');
30
30
  });
31
31
  });
@@ -36,17 +36,17 @@ describe('CacheApi', () => {
36
36
  it('应该在成功调用后返回缓存的值', async () => {
37
37
  const expectedResult = 'test-result';
38
38
  mockApiFunc.mockResolvedValue(expectedResult);
39
- await cacheApi.send('param1', 123);
39
+ await cacheApi.call('param1', 123);
40
40
  expect(cacheApi.value).toBe(expectedResult);
41
41
  });
42
42
  it('应该在多次调用后返回最新的缓存值', async () => {
43
43
  const result1 = 'result-1';
44
44
  const result2 = 'result-2';
45
45
  mockApiFunc.mockResolvedValueOnce(result1);
46
- await cacheApi.send('param1', 123);
46
+ await cacheApi.call('param1', 123);
47
47
  expect(cacheApi.value).toBe(result1);
48
48
  mockApiFunc.mockResolvedValueOnce(result2);
49
- await cacheApi.send('param2', 456);
49
+ await cacheApi.call('param2', 456);
50
50
  expect(cacheApi.value).toBe(result2);
51
51
  });
52
52
  });
@@ -56,14 +56,14 @@ describe('CacheApi', () => {
56
56
  });
57
57
  it('成功调用后应该返回 false', async () => {
58
58
  mockApiFunc.mockResolvedValue('test-result');
59
- await cacheApi.send('param1', 123);
59
+ await cacheApi.call('param1', 123);
60
60
  expect(cacheApi.empty).toBe(false);
61
61
  });
62
62
  it('即使调用失败也应该保持 true', async () => {
63
63
  const error = new Error('API Error');
64
64
  mockApiFunc.mockRejectedValue(error);
65
65
  try {
66
- await cacheApi.send('param1', 123);
66
+ await cacheApi.call('param1', 123);
67
67
  }
68
68
  catch (e) {
69
69
  // 忽略错误
@@ -81,7 +81,7 @@ describe('CacheApi', () => {
81
81
  it('应该调用传入的 API 函数', async () => {
82
82
  const expectedResult = 'api-result';
83
83
  mockApiFunc.mockResolvedValue(expectedResult);
84
- const result = await cacheApi.send('test', 42);
84
+ const result = await cacheApi.call('test', 42);
85
85
  expect(mockApiFunc).toHaveBeenCalledTimes(1);
86
86
  expect(mockApiFunc).toHaveBeenCalledWith('test', 42);
87
87
  expect(result).toBe(expectedResult);
@@ -89,19 +89,19 @@ describe('CacheApi', () => {
89
89
  it('应该正确传递多个参数', async () => {
90
90
  const params = ['hello', 999];
91
91
  mockApiFunc.mockResolvedValue('success');
92
- await cacheApi.send(...params);
92
+ await cacheApi.call(...params);
93
93
  expect(mockApiFunc).toHaveBeenCalledWith(...params);
94
94
  });
95
95
  it('应该返回 API 函数的结果', async () => {
96
96
  const expectedResult = { data: 'test', status: 'ok' };
97
97
  mockApiFunc.mockResolvedValue(expectedResult);
98
- const result = await cacheApi.send('param', 1);
98
+ const result = await cacheApi.call('param', 1);
99
99
  expect(result).toEqual(expectedResult);
100
100
  });
101
101
  it('应该处理 API 函数抛出的异常', async () => {
102
102
  const error = new Error('API Error');
103
103
  mockApiFunc.mockRejectedValue(error);
104
- await expect(cacheApi.send('param', 1)).rejects.toThrow('API Error');
104
+ await expect(cacheApi.call('param', 1)).rejects.toThrow('API Error');
105
105
  });
106
106
  });
107
107
  describe('缓存功能', () => {
@@ -109,11 +109,11 @@ describe('CacheApi', () => {
109
109
  const result = 'cached-result';
110
110
  mockApiFunc.mockResolvedValue(result);
111
111
  // 第一次调用
112
- const firstResult = await cacheApi.send('same', 123);
112
+ const firstResult = await cacheApi.call('same', 123);
113
113
  expect(firstResult).toBe(result);
114
114
  expect(cacheApi.value).toBe(result);
115
115
  // 第二次调用相同参数,应该从缓存返回
116
- const secondResult = await cacheApi.send('same', 123);
116
+ const secondResult = await cacheApi.call('same', 123);
117
117
  expect(secondResult).toBe(result);
118
118
  expect(cacheApi.value).toBe(result);
119
119
  // API 函数应该被调用两次(SideCache 的 handle 方法会每次都调用)
@@ -122,8 +122,8 @@ describe('CacheApi', () => {
122
122
  it('不同参数应该触发新的 API 调用', async () => {
123
123
  mockApiFunc.mockResolvedValueOnce('result1');
124
124
  mockApiFunc.mockResolvedValueOnce('result2');
125
- await cacheApi.send('param1', 1);
126
- await cacheApi.send('param2', 2);
125
+ await cacheApi.call('param1', 1);
126
+ await cacheApi.call('param2', 2);
127
127
  expect(mockApiFunc).toHaveBeenCalledTimes(2);
128
128
  expect(mockApiFunc).toHaveBeenNthCalledWith(1, 'param1', 1);
129
129
  expect(mockApiFunc).toHaveBeenNthCalledWith(2, 'param2', 2);
@@ -131,9 +131,9 @@ describe('CacheApi', () => {
131
131
  it('应该正确更新当前缓存的 key', async () => {
132
132
  mockApiFunc.mockResolvedValueOnce('value1');
133
133
  mockApiFunc.mockResolvedValueOnce('value2');
134
- await cacheApi.send('key1', 1);
134
+ await cacheApi.call('key1', 1);
135
135
  expect(cacheApi.value).toBe('value1');
136
- await cacheApi.send('key2', 2);
136
+ await cacheApi.call('key2', 2);
137
137
  expect(cacheApi.value).toBe('value2');
138
138
  });
139
139
  });
@@ -145,9 +145,9 @@ describe('CacheApi', () => {
145
145
  return `result-${param}-${++resolveCount}`;
146
146
  });
147
147
  const [result1, result2, result3] = await Promise.all([
148
- cacheApi.send('param1', 1),
149
- cacheApi.send('param2', 2),
150
- cacheApi.send('param3', 3)
148
+ cacheApi.call('param1', 1),
149
+ cacheApi.call('param2', 2),
150
+ cacheApi.call('param3', 3)
151
151
  ]);
152
152
  expect(result1).toMatch(/result-param1-\d/);
153
153
  expect(result2).toMatch(/result-param2-\d/);
@@ -161,7 +161,7 @@ describe('CacheApi', () => {
161
161
  return 'delayed-result';
162
162
  });
163
163
  // 开始异步操作,此时 value 应该还是之前的值
164
- const promise = cacheApi.send('test', 1);
164
+ const promise = cacheApi.call('test', 1);
165
165
  // 等待一小段时间,但还没完成
166
166
  await new Promise(resolve => setTimeout(resolve, delay / 2));
167
167
  // 完成异步操作
@@ -173,13 +173,13 @@ describe('CacheApi', () => {
173
173
  describe('边缘情况', () => {
174
174
  it('应该处理 null 返回值', async () => {
175
175
  mockApiFunc.mockResolvedValue(null);
176
- const result = await cacheApi.send('test', 1);
176
+ const result = await cacheApi.call('test', 1);
177
177
  expect(result).toBeNull();
178
178
  expect(cacheApi.value).toBeNull();
179
179
  });
180
180
  it('应该处理 undefined 返回值', async () => {
181
181
  mockApiFunc.mockResolvedValue(undefined);
182
- const result = await cacheApi.send('test', 1);
182
+ const result = await cacheApi.call('test', 1);
183
183
  expect(result).toBeUndefined();
184
184
  expect(cacheApi.value).toBeUndefined();
185
185
  });
@@ -189,13 +189,13 @@ describe('CacheApi', () => {
189
189
  complexMockFunc.mockResolvedValue('complex-result');
190
190
  // 创建一个接受复杂参数的 CacheApi
191
191
  const complexCacheApi = new CacheApi(complexMockFunc);
192
- const result = await complexCacheApi.send(complexParam);
192
+ const result = await complexCacheApi.call(complexParam);
193
193
  expect(result).toBe('complex-result');
194
194
  expect(complexMockFunc).toHaveBeenCalledWith(complexParam);
195
195
  });
196
196
  it('should handle no parameters', async () => {
197
197
  const noParamApi = new CacheApi(() => Promise.resolve('no-param-result'));
198
- const result = await noParamApi.send();
198
+ const result = await noParamApi.call();
199
199
  expect(result).toBe('no-param-result');
200
200
  });
201
201
  });
@@ -221,7 +221,7 @@ describe('CacheApi', () => {
221
221
  return reaction;
222
222
  });
223
223
  mockApiFunc.mockResolvedValue('new-value');
224
- await cacheApi.send('test', 1);
224
+ await cacheApi.call('test', 1);
225
225
  // 清理
226
226
  if (typeof disposer === 'function') {
227
227
  disposer();
@@ -237,7 +237,7 @@ describe('CacheApi', () => {
237
237
  return Promise.resolve({ result: `${str}-${num}-${bool}` });
238
238
  });
239
239
  // 正确的调用
240
- expect(() => typedApi.send('test', 42, true)).not.toThrow();
240
+ expect(() => typedApi.call('test', 42, true)).not.toThrow();
241
241
  // 以下调用在 TypeScript 中会产生编译错误(在运行时测试中跳过)
242
242
  // typedApi.send('test', 'wrong-type', true) // 第二个参数应该是 number
243
243
  // typedApi.send('test', 42) // 缺少第三个参数
@@ -254,7 +254,7 @@ describe('CacheApi', () => {
254
254
  });
255
255
  mockApiFunc.mockReturnValue(promise);
256
256
  // 开始请求
257
- const sendPromise = cacheApi.send('test', 1);
257
+ const sendPromise = cacheApi.call('test', 1);
258
258
  // 此时应该是 loading 状态
259
259
  expect(cacheApi.loading).toBe(true);
260
260
  // 完成请求
@@ -267,7 +267,7 @@ describe('CacheApi', () => {
267
267
  const error = new Error('API Error');
268
268
  mockApiFunc.mockRejectedValue(error);
269
269
  try {
270
- await cacheApi.send('test', 1);
270
+ await cacheApi.call('test', 1);
271
271
  }
272
272
  catch (e) {
273
273
  // 忽略错误
@@ -282,9 +282,9 @@ describe('CacheApi', () => {
282
282
  });
283
283
  });
284
284
  // 启动三个并发请求
285
- const promise1 = cacheApi.send('req1', 1);
286
- const promise2 = cacheApi.send('req2', 2);
287
- const promise3 = cacheApi.send('req3', 3);
285
+ const promise1 = cacheApi.call('req1', 1);
286
+ const promise2 = cacheApi.call('req2', 2);
287
+ const promise3 = cacheApi.call('req3', 3);
288
288
  // 此时应该有三个请求正在进行,loading 为 true
289
289
  expect(cacheApi.loading).toBe(true);
290
290
  // 完成第一个请求
@@ -319,8 +319,8 @@ describe('CacheApi', () => {
319
319
  }
320
320
  });
321
321
  // 启动两个请求,一个成功一个失败
322
- const successPromise = cacheApi.send('success', 1);
323
- const errorPromise = cacheApi.send('error', 2);
322
+ const successPromise = cacheApi.call('success', 1);
323
+ const errorPromise = cacheApi.call('error', 2);
324
324
  expect(cacheApi.loading).toBe(true);
325
325
  // 先让失败的请求完成
326
326
  rejectError(new Error('Failed'));
@@ -345,4 +345,105 @@ describe('CacheApi', () => {
345
345
  expect(descriptor === null || descriptor === void 0 ? void 0 : descriptor.set).toBeUndefined();
346
346
  });
347
347
  });
348
+ describe('refresh 方法', () => {
349
+ it('应该在没有调用过 call 时抛出错误', async () => {
350
+ await expect(cacheApi.refresh()).rejects.toThrow('没有可用的参数来刷新数据,请先调用 call 方法');
351
+ });
352
+ it('应该使用最近一次的参数重新调用 API', async () => {
353
+ const expectedResult1 = 'first-result';
354
+ const expectedResult2 = 'refreshed-result';
355
+ mockApiFunc.mockResolvedValueOnce(expectedResult1);
356
+ mockApiFunc.mockResolvedValueOnce(expectedResult2);
357
+ // 第一次调用
358
+ await cacheApi.call('param1', 123);
359
+ expect(cacheApi.value).toBe(expectedResult1);
360
+ expect(mockApiFunc).toHaveBeenCalledTimes(1);
361
+ expect(mockApiFunc).toHaveBeenCalledWith('param1', 123);
362
+ // 刷新
363
+ const refreshResult = await cacheApi.refresh();
364
+ expect(refreshResult).toBe(expectedResult2);
365
+ expect(cacheApi.value).toBe(expectedResult2);
366
+ expect(mockApiFunc).toHaveBeenCalledTimes(2);
367
+ expect(mockApiFunc).toHaveBeenNthCalledWith(2, 'param1', 123);
368
+ });
369
+ it('应该在多次调用后使用最新的参数进行刷新', async () => {
370
+ mockApiFunc.mockResolvedValue('result');
371
+ // 第一次调用
372
+ await cacheApi.call('param1', 123);
373
+ // 第二次调用,参数不同
374
+ await cacheApi.call('param2', 456);
375
+ // 刷新应该使用最新的参数
376
+ await cacheApi.refresh();
377
+ expect(mockApiFunc).toHaveBeenCalledTimes(3);
378
+ expect(mockApiFunc).toHaveBeenNthCalledWith(3, 'param2', 456);
379
+ });
380
+ it('应该在 force=false 时正常刷新(默认行为)', async () => {
381
+ const result1 = 'cached-result';
382
+ const result2 = 'refreshed-result';
383
+ mockApiFunc.mockResolvedValueOnce(result1);
384
+ mockApiFunc.mockResolvedValueOnce(result2);
385
+ await cacheApi.call('test', 1);
386
+ const refreshResult = await cacheApi.refresh(false);
387
+ expect(refreshResult).toBe(result2);
388
+ expect(mockApiFunc).toHaveBeenCalledTimes(2);
389
+ });
390
+ it('应该在 force=true 时强制刷新并清除缓存', async () => {
391
+ const result1 = 'cached-result';
392
+ const result2 = 'force-refreshed-result';
393
+ mockApiFunc.mockResolvedValueOnce(result1);
394
+ mockApiFunc.mockResolvedValueOnce(result2);
395
+ await cacheApi.call('test', 1);
396
+ const refreshResult = await cacheApi.refresh(true);
397
+ expect(refreshResult).toBe(result2);
398
+ expect(mockApiFunc).toHaveBeenCalledTimes(2);
399
+ });
400
+ it('应该正确处理刷新时的异常', async () => {
401
+ const error = new Error('Refresh failed');
402
+ mockApiFunc.mockResolvedValueOnce('initial-result');
403
+ mockApiFunc.mockRejectedValueOnce(error);
404
+ // 第一次调用成功
405
+ await cacheApi.call('test', 1);
406
+ expect(cacheApi.value).toBe('initial-result');
407
+ // 刷新时失败
408
+ await expect(cacheApi.refresh()).rejects.toThrow('Refresh failed');
409
+ // 值应该保持不变
410
+ expect(cacheApi.value).toBe('initial-result');
411
+ });
412
+ it('应该在刷新期间正确更新 loading 状态', async () => {
413
+ let resolveFn;
414
+ const promise = new Promise((resolve) => {
415
+ resolveFn = resolve;
416
+ });
417
+ mockApiFunc.mockResolvedValueOnce('initial');
418
+ mockApiFunc.mockReturnValueOnce(promise);
419
+ // 初始调用
420
+ await cacheApi.call('test', 1);
421
+ expect(cacheApi.loading).toBe(false);
422
+ // 开始刷新
423
+ const refreshPromise = cacheApi.refresh();
424
+ expect(cacheApi.loading).toBe(true);
425
+ // 完成刷新
426
+ resolveFn('refreshed');
427
+ await refreshPromise;
428
+ expect(cacheApi.loading).toBe(false);
429
+ });
430
+ it('应该正确处理复杂参数的刷新', async () => {
431
+ const complexParam = { id: 1, data: { nested: 'value' } };
432
+ const complexMockFunc = vi.fn();
433
+ complexMockFunc.mockResolvedValue('complex-result');
434
+ const complexCacheApi = new CacheApi(complexMockFunc);
435
+ await complexCacheApi.call(complexParam);
436
+ await complexCacheApi.refresh();
437
+ expect(complexMockFunc).toHaveBeenCalledTimes(2);
438
+ expect(complexMockFunc).toHaveBeenNthCalledWith(2, complexParam);
439
+ });
440
+ it('应该支持无参数函数的刷新', async () => {
441
+ const noParamMockFunc = vi.fn();
442
+ noParamMockFunc.mockResolvedValue('no-param-result');
443
+ const noParamCacheApi = new CacheApi(noParamMockFunc);
444
+ await noParamCacheApi.call();
445
+ await noParamCacheApi.refresh();
446
+ expect(noParamMockFunc).toHaveBeenCalledTimes(2);
447
+ });
448
+ });
348
449
  });
@@ -6,5 +6,6 @@ export declare class SideCache<T> {
6
6
  get empty(): boolean;
7
7
  handle<F extends ((...args: unknown[]) => T)>(key: unknown, func: F): T;
8
8
  handle<F extends ((...args: unknown[]) => Promise<T> | T)>(key: unknown, func: F): Promise<T> | T;
9
+ clear(key?: unknown): void;
9
10
  }
10
11
  //# sourceMappingURL=side-cache.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"side-cache.d.ts","sourceRoot":"","sources":["../../source/side-cache/side-cache.ts"],"names":[],"mappings":"AAWA,qBAAa,SAAS,CAAC,CAAC;IAEtB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgB;IAG1C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoB;IAG/C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoC;IAE1D,IACW,KAAK,IAAI,CAAC,GAAG,SAAS,CAIhC;IAED,IACW,KAAK,IAAI,OAAO,CAE1B;IAED,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC;IACvE,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;CAuClG"}
1
+ {"version":3,"file":"side-cache.d.ts","sourceRoot":"","sources":["../../source/side-cache/side-cache.ts"],"names":[],"mappings":"AAWA,qBAAa,SAAS,CAAC,CAAC;IAEtB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgB;IAG1C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoB;IAG/C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoC;IAE1D,IACW,KAAK,IAAI,CAAC,GAAG,SAAS,CAIhC;IAED,IACW,KAAK,IAAI,OAAO,CAE1B;IAED,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC;IACvE,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IAyC1F,KAAK,CAAC,GAAG,CAAC,EAAE,OAAO,GAAG,IAAI;CAoBlC"}
@@ -49,7 +49,7 @@ function isPromiseLike(value) {
49
49
  }
50
50
  let SideCache = (() => {
51
51
  var _a, _SideCache_emptyFlag_accessor_storage, _SideCache_currentKey_accessor_storage, _SideCache_cache_accessor_storage;
52
- var _b, _c;
52
+ var _b, _c, _d;
53
53
  let _instanceExtraInitializers = [];
54
54
  let _emptyFlag_decorators;
55
55
  let _emptyFlag_initializers = [];
@@ -63,6 +63,7 @@ let SideCache = (() => {
63
63
  let _get_value_decorators;
64
64
  let _get_empty_decorators;
65
65
  let _handle_decorators;
66
+ let _clear_decorators;
66
67
  return _a = class SideCache {
67
68
  get emptyFlag() { return __classPrivateFieldGet(this, _SideCache_emptyFlag_accessor_storage, "f"); }
68
69
  set emptyFlag(value) { __classPrivateFieldSet(this, _SideCache_emptyFlag_accessor_storage, value, "f"); }
@@ -106,6 +107,27 @@ let SideCache = (() => {
106
107
  });
107
108
  return funcReturn;
108
109
  }
110
+ clear(key) {
111
+ var _b;
112
+ if (key === undefined) {
113
+ // 清除所有缓存
114
+ this.cache = {};
115
+ this.emptyFlag = true;
116
+ this.currentKey = undefined;
117
+ }
118
+ else {
119
+ // 清除指定 key 的缓存
120
+ const keyStringify = (_b = JSON.stringify(key)) !== null && _b !== void 0 ? _b : 'undefined';
121
+ const newCache = Object.assign({}, this.cache);
122
+ delete newCache[keyStringify];
123
+ this.cache = newCache;
124
+ // 如果清除的是当前 key,需要重置状态
125
+ if (this.currentKey === keyStringify) {
126
+ this.emptyFlag = Object.keys(this.cache).length === 0;
127
+ this.currentKey = undefined;
128
+ }
129
+ }
130
+ }
109
131
  constructor() {
110
132
  _SideCache_emptyFlag_accessor_storage.set(this, (__runInitializers(this, _instanceExtraInitializers), __runInitializers(this, _emptyFlag_initializers, true)));
111
133
  _SideCache_currentKey_accessor_storage.set(this, (__runInitializers(this, _emptyFlag_extraInitializers), __runInitializers(this, _currentKey_initializers, void 0)));
@@ -124,12 +146,14 @@ let SideCache = (() => {
124
146
  _get_value_decorators = [computed];
125
147
  _get_empty_decorators = [computed];
126
148
  _handle_decorators = [(_c = action).bound.bind(_c)];
149
+ _clear_decorators = [(_d = action).bound.bind(_d)];
127
150
  __esDecorate(_a, null, _emptyFlag_decorators, { kind: "accessor", name: "emptyFlag", static: false, private: false, access: { has: obj => "emptyFlag" in obj, get: obj => obj.emptyFlag, set: (obj, value) => { obj.emptyFlag = value; } }, metadata: _metadata }, _emptyFlag_initializers, _emptyFlag_extraInitializers);
128
151
  __esDecorate(_a, null, _currentKey_decorators, { kind: "accessor", name: "currentKey", static: false, private: false, access: { has: obj => "currentKey" in obj, get: obj => obj.currentKey, set: (obj, value) => { obj.currentKey = value; } }, metadata: _metadata }, _currentKey_initializers, _currentKey_extraInitializers);
129
152
  __esDecorate(_a, null, _cache_decorators, { kind: "accessor", name: "cache", static: false, private: false, access: { has: obj => "cache" in obj, get: obj => obj.cache, set: (obj, value) => { obj.cache = value; } }, metadata: _metadata }, _cache_initializers, _cache_extraInitializers);
130
153
  __esDecorate(_a, null, _get_value_decorators, { kind: "getter", name: "value", static: false, private: false, access: { has: obj => "value" in obj, get: obj => obj.value }, metadata: _metadata }, null, _instanceExtraInitializers);
131
154
  __esDecorate(_a, null, _get_empty_decorators, { kind: "getter", name: "empty", static: false, private: false, access: { has: obj => "empty" in obj, get: obj => obj.empty }, metadata: _metadata }, null, _instanceExtraInitializers);
132
155
  __esDecorate(_a, null, _handle_decorators, { kind: "method", name: "handle", static: false, private: false, access: { has: obj => "handle" in obj, get: obj => obj.handle }, metadata: _metadata }, null, _instanceExtraInitializers);
156
+ __esDecorate(_a, null, _clear_decorators, { kind: "method", name: "clear", static: false, private: false, access: { has: obj => "clear" in obj, get: obj => obj.clear }, metadata: _metadata }, null, _instanceExtraInitializers);
133
157
  if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
134
158
  })(),
135
159
  _a;
@@ -1,4 +1,5 @@
1
1
  import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { runInAction } from 'mobx';
2
3
  import { SideCache } from './side-cache';
3
4
  describe('SideCache', () => {
4
5
  let cache;
@@ -176,4 +177,95 @@ describe('SideCache', () => {
176
177
  }
177
178
  });
178
179
  });
180
+ describe('clear 方法', () => {
181
+ it('应该能够清除指定 key 的缓存', () => {
182
+ const mockFunc = vi.fn(() => 'test-result');
183
+ const key = 'test-key';
184
+ // 先添加缓存
185
+ cache.handle(key, mockFunc);
186
+ expect(cache.empty).toBe(false);
187
+ expect(cache.value).toBe('test-result');
188
+ // 清除指定 key 的缓存
189
+ cache.clear(key);
190
+ expect(cache.empty).toBe(true);
191
+ expect(cache.value).toBe(undefined);
192
+ });
193
+ it('应该能够清除当前激活的缓存', () => {
194
+ const mockFunc = vi.fn(() => 'active-result');
195
+ const key = 'active-key';
196
+ cache.handle(key, mockFunc);
197
+ expect(cache.value).toBe('active-result');
198
+ // 清除当前激活的 key
199
+ cache.clear(key);
200
+ expect(cache.value).toBe(undefined);
201
+ expect(cache.empty).toBe(true);
202
+ });
203
+ it('应该能够清除所有缓存', () => {
204
+ const mockFunc1 = vi.fn(() => 'result1');
205
+ const mockFunc2 = vi.fn(() => 'result2');
206
+ // 添加多个缓存
207
+ cache.handle('key1', mockFunc1);
208
+ cache.handle('key2', mockFunc2);
209
+ expect(cache.value).toBe('result2');
210
+ expect(cache.empty).toBe(false);
211
+ // 清除所有缓存
212
+ cache.clear();
213
+ expect(cache.value).toBe(undefined);
214
+ expect(cache.empty).toBe(true);
215
+ });
216
+ it('应该能够清除非当前激活的缓存而不影响当前状态', () => {
217
+ const mockFunc1 = vi.fn(() => 'result1');
218
+ const mockFunc2 = vi.fn(() => 'result2');
219
+ // 添加两个缓存
220
+ cache.handle('key1', mockFunc1);
221
+ cache.handle('key2', mockFunc2);
222
+ expect(cache.value).toBe('result2'); // 当前激活的是 key2
223
+ // 清除非当前激活的 key1
224
+ cache.clear('key1');
225
+ expect(cache.value).toBe('result2'); // 当前值不变
226
+ expect(cache.empty).toBe(false); // 仍有缓存存在
227
+ });
228
+ it('应该正确处理清除不存在的 key', () => {
229
+ const mockFunc = vi.fn(() => 'test-result');
230
+ cache.handle('existing-key', mockFunc);
231
+ // 清除不存在的 key 不应该影响现有缓存
232
+ cache.clear('non-existing-key');
233
+ expect(cache.value).toBe('test-result');
234
+ expect(cache.empty).toBe(false);
235
+ });
236
+ it('应该正确处理复杂对象作为 key', () => {
237
+ const complexKey = { id: 1, data: { nested: 'value' } };
238
+ const mockFunc = vi.fn(() => 'complex-result');
239
+ // 使用复杂对象作为 key
240
+ cache.handle(complexKey, mockFunc);
241
+ expect(cache.value).toBe('complex-result');
242
+ // 清除复杂对象 key
243
+ cache.clear(complexKey);
244
+ expect(cache.value).toBe(undefined);
245
+ expect(cache.empty).toBe(true);
246
+ });
247
+ it('应该正确处理 undefined 作为 key', () => {
248
+ const mockFunc = vi.fn(() => 'undefined-key-result');
249
+ // 使用 undefined 作为 key
250
+ cache.handle(undefined, mockFunc);
251
+ expect(cache.value).toBe('undefined-key-result');
252
+ // 清除 undefined key
253
+ cache.clear(undefined);
254
+ expect(cache.value).toBe(undefined);
255
+ expect(cache.empty).toBe(true);
256
+ });
257
+ it('应该在 MobX action 中正确更新状态', () => {
258
+ const mockFunc = vi.fn(() => 'action-result');
259
+ const key = 'action-key';
260
+ runInAction(() => {
261
+ cache.handle(key, mockFunc);
262
+ });
263
+ expect(cache.value).toBe('action-result');
264
+ runInAction(() => {
265
+ cache.clear(key);
266
+ });
267
+ expect(cache.value).toBe(undefined);
268
+ expect(cache.empty).toBe(true);
269
+ });
270
+ });
179
271
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taicode/common-web",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "author": "Alain",
5
5
  "license": "ISC",
6
6
  "description": "",