Skip to content

Commit

Permalink
fix(property-provider): stop memoizing rejected provider (#2680)
Browse files Browse the repository at this point in the history
  • Loading branch information
AllanZhengYP committed Aug 17, 2021
1 parent cbdcd9c commit fac5f27
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 17 deletions.
43 changes: 34 additions & 9 deletions packages/property-provider/src/memoize.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,28 @@ describe("memoize", () => {
const memoized = memoize(provider);
expect(provider).toHaveBeenCalledTimes(0);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
for (const index in [...Array(repeatTimes).keys()]) {
for (const _ in [...Array(repeatTimes).keys()]) {
expect(await memoized()).toStrictEqual(mockReturn);
expect(provider).toHaveBeenCalledTimes(1);
}
});

it("should always return the same promise", () => {
expect.assertions(repeatTimes * 2);

it("should retry provider if previous provider is failed", async () => {
provider
.mockReset()
.mockRejectedValueOnce("Error")
.mockResolvedValueOnce("Retry")
.mockRejectedValueOnce("Should not call 3rd time");
const memoized = memoize(provider);
const result = memoized();
// eslint-disable-next-line @typescript-eslint/no-unused-vars
for (const index in [...Array(repeatTimes).keys()]) {
expect(memoized()).toStrictEqual(result);
expect(provider).toHaveBeenCalledTimes(1);
try {
await memoized();
fail();
} catch (e) {
expect(e).toBe("Error");
}
expect(await memoized()).toBe("Retry");
expect(await memoized()).toBe("Retry");
expect(provider).toBeCalledTimes(2);
});
});

Expand Down Expand Up @@ -124,5 +130,24 @@ describe("memoize", () => {
return requiresRefreshFalseTest();
});
});

it("should retry provider if previous provider is failed", async () => {
provider
.mockReset()
.mockRejectedValueOnce("Error")
.mockResolvedValueOnce("Retry")
.mockRejectedValueOnce("Should not call 3rd time");
isExpired.mockReset().mockReturnValue(false);
const memoized = memoize(provider, isExpired);
try {
await memoized();
fail();
} catch (e) {
expect(e).toBe("Error");
}
expect(await memoized()).toBe("Retry");
expect(await memoized()).toBe("Retry");
expect(provider).toBeCalledTimes(2);
});
});
});
15 changes: 7 additions & 8 deletions packages/property-provider/src/memoize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,37 +45,36 @@ export const memoize: MemoizeOverload = <T>(
isExpired?: (resolved: T) => boolean,
requiresRefresh?: (resolved: T) => boolean
): Provider<T> => {
let result: any;
let resolved: any;
let hasResult: boolean;
if (isExpired === undefined) {
// This is a static memoization; no need to incorporate refreshing
return () => {
return async () => {
if (!hasResult) {
result = provider();
resolved = await provider();
hasResult = true;
}
return result;
return resolved;
};
}

let isConstant = false;

return async () => {
if (!hasResult) {
result = provider();
resolved = await provider();
hasResult = true;
}
if (isConstant) {
return result;
return resolved;
}

const resolved = await result;
if (requiresRefresh && !requiresRefresh(resolved)) {
isConstant = true;
return resolved;
}
if (isExpired(resolved)) {
return (result = provider());
return (resolved = await provider());
}
return resolved;
};
Expand Down

0 comments on commit fac5f27

Please sign in to comment.