Skip to content

Commit f742fac

Browse files
authored
Links preview: cache requests to API (#538)
Keep a cache of all the API request calls done and re-use them when the same link is previewed again. It follows the same logic we use on docdiff.
1 parent be5ee1c commit f742fac

File tree

3 files changed

+37
-14
lines changed

3 files changed

+37
-14
lines changed

src/linkpreviews.js

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ const HIDE_TOOLTIP_DELAY = IS_TESTING ? 0 : 300;
2626

2727
const TOOLTIP_DATA_HREF = "data-linkpreview-href";
2828

29+
// Object to save the responses from the EmbedAPI.
30+
// This way we don't have to perform multiple times the same request.
31+
// The key is the URL and the value is the JSON response.
32+
const cachedRemoteResponses = {};
33+
2934
function setupTooltip(el, doctoolname, doctoolversion, selector) {
3035
// Take the provided element and setup the listeners required to
3136
// make the linkpreviews work
@@ -86,19 +91,31 @@ function setupTooltip(el, doctoolname, doctoolversion, selector) {
8691
if (newTooltip !== undefined) {
8792
const url = getEmbedURL(anchorElement.href);
8893

89-
fetch(url, {
90-
method: "GET",
91-
headers: {
92-
"X-RTD-Hosting-Integrations-Version": CLIENT_VERSION,
93-
},
94-
})
95-
.then((response) => {
94+
let promiseData;
95+
// Check if we have the response already cached
96+
if (Object.keys(cachedRemoteResponses).includes(url)) {
97+
console.debug("URL was found cached, reusing it.");
98+
promiseData = Promise.resolve(cachedRemoteResponses[url]);
99+
} else {
100+
console.debug("URL not found cached, performing a fetch.");
101+
promiseData = fetch(url, {
102+
method: "GET",
103+
headers: {
104+
"X-RTD-Hosting-Integrations-Version": CLIENT_VERSION,
105+
},
106+
}).then((response) => {
96107
if (!response.ok) {
97108
throw new Error("Error hitting Read the Docs embed API");
98109
}
99110
return response.json();
100-
})
111+
});
112+
}
113+
114+
promiseData
101115
.then((data) => {
116+
// Cache the response to use it later
117+
cachedRemoteResponses[url] = data;
118+
102119
// TODO: decide whether or not to truncate the content
103120
// Do we want to have "modals" as well? are those useful?
104121
const content = data["content"];

tests/__snapshots__/search.test.snap.js

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/search.test.html

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,9 @@
7474
document.dispatchEvent(searchEvent);
7575

7676
await elementUpdated(element);
77-
await expect(element).shadowDom.to.equalSnapshot();
77+
await expect(element).shadowDom.to.equalSnapshot({
78+
ignoreAttributes: [{ tags: ["form"], attributes: ["class"] }],
79+
});
7880
});
7981

8082
it("show the modal and perform a query with no results", async () => {
@@ -104,7 +106,9 @@
104106
),
105107
"No-results block was not rendered",
106108
);
107-
await expect(element).shadowDom.to.equalSnapshot();
109+
await expect(element).shadowDom.to.equalSnapshot({
110+
ignoreAttributes: [{ tags: ["form"], attributes: ["class"] }],
111+
});
108112
});
109113

110114
it("show the modal and perform a query", async () => {
@@ -130,7 +134,9 @@
130134
() => element.shadowRoot.querySelector("div.results > div.hit"),
131135
"Hit result was not rendered",
132136
);
133-
await expect(element).shadowDom.to.equalSnapshot();
137+
await expect(element).shadowDom.to.equalSnapshot({
138+
ignoreAttributes: [{ tags: ["form"], attributes: ["class"] }],
139+
});
134140
});
135141
});
136142
});

0 commit comments

Comments
 (0)