Skip to content

Commit fac5f27

Browse files
authored
fix(property-provider): stop memoizing rejected provider (#2680)
1 parent cbdcd9c commit fac5f27

File tree

2 files changed

+41
-17
lines changed

2 files changed

+41
-17
lines changed

packages/property-provider/src/memoize.spec.ts

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,28 @@ describe("memoize", () => {
2020
const memoized = memoize(provider);
2121
expect(provider).toHaveBeenCalledTimes(0);
2222
// eslint-disable-next-line @typescript-eslint/no-unused-vars
23-
for (const index in [...Array(repeatTimes).keys()]) {
23+
for (const _ in [...Array(repeatTimes).keys()]) {
2424
expect(await memoized()).toStrictEqual(mockReturn);
2525
expect(provider).toHaveBeenCalledTimes(1);
2626
}
2727
});
2828

29-
it("should always return the same promise", () => {
30-
expect.assertions(repeatTimes * 2);
31-
29+
it("should retry provider if previous provider is failed", async () => {
30+
provider
31+
.mockReset()
32+
.mockRejectedValueOnce("Error")
33+
.mockResolvedValueOnce("Retry")
34+
.mockRejectedValueOnce("Should not call 3rd time");
3235
const memoized = memoize(provider);
33-
const result = memoized();
34-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
35-
for (const index in [...Array(repeatTimes).keys()]) {
36-
expect(memoized()).toStrictEqual(result);
37-
expect(provider).toHaveBeenCalledTimes(1);
36+
try {
37+
await memoized();
38+
fail();
39+
} catch (e) {
40+
expect(e).toBe("Error");
3841
}
42+
expect(await memoized()).toBe("Retry");
43+
expect(await memoized()).toBe("Retry");
44+
expect(provider).toBeCalledTimes(2);
3945
});
4046
});
4147

@@ -124,5 +130,24 @@ describe("memoize", () => {
124130
return requiresRefreshFalseTest();
125131
});
126132
});
133+
134+
it("should retry provider if previous provider is failed", async () => {
135+
provider
136+
.mockReset()
137+
.mockRejectedValueOnce("Error")
138+
.mockResolvedValueOnce("Retry")
139+
.mockRejectedValueOnce("Should not call 3rd time");
140+
isExpired.mockReset().mockReturnValue(false);
141+
const memoized = memoize(provider, isExpired);
142+
try {
143+
await memoized();
144+
fail();
145+
} catch (e) {
146+
expect(e).toBe("Error");
147+
}
148+
expect(await memoized()).toBe("Retry");
149+
expect(await memoized()).toBe("Retry");
150+
expect(provider).toBeCalledTimes(2);
151+
});
127152
});
128153
});

packages/property-provider/src/memoize.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,37 +45,36 @@ export const memoize: MemoizeOverload = <T>(
4545
isExpired?: (resolved: T) => boolean,
4646
requiresRefresh?: (resolved: T) => boolean
4747
): Provider<T> => {
48-
let result: any;
48+
let resolved: any;
4949
let hasResult: boolean;
5050
if (isExpired === undefined) {
5151
// This is a static memoization; no need to incorporate refreshing
52-
return () => {
52+
return async () => {
5353
if (!hasResult) {
54-
result = provider();
54+
resolved = await provider();
5555
hasResult = true;
5656
}
57-
return result;
57+
return resolved;
5858
};
5959
}
6060

6161
let isConstant = false;
6262

6363
return async () => {
6464
if (!hasResult) {
65-
result = provider();
65+
resolved = await provider();
6666
hasResult = true;
6767
}
6868
if (isConstant) {
69-
return result;
69+
return resolved;
7070
}
7171

72-
const resolved = await result;
7372
if (requiresRefresh && !requiresRefresh(resolved)) {
7473
isConstant = true;
7574
return resolved;
7675
}
7776
if (isExpired(resolved)) {
78-
return (result = provider());
77+
return (resolved = await provider());
7978
}
8079
return resolved;
8180
};

0 commit comments

Comments
 (0)