I have some code calling to load the same template really fast. I’ve tried to implement a simple caching system to only fetch when the template wasn’t previously loaded, but I can’t seem to get the await to truly wait until the function is completed.
The code for the template loading system:
var arrContent = []; //array of objects: {"url":"http://...", "content": "<div>..."}
var content = null;
this.loadFile = async function(url){
//Check if the content was already loaded
let i = findContentIndex(url);
if(i != null){ // The template already exist, simply load it from memory
console.log("Cached!");
content = arrContent[i].content;
}else{
//Content is not already in cache, load it from the url
console.log("Fetching...");
await fetch(url)
.then(function(response){
return response.text();
})
.then(function(response) {
content = response;
arrContent.push({"url": url, "content": content});
})
.catch(
function() {
error => console.log(error);
}
);
console.log("content");
}
}
function findContentIndex(url){
for(let i=0; i<arrContent.length; i++)
if(arrContent[i].url != undefined && arrContent[i].url == url)
return i;
return null;
}
this.render = function(){
//...
}
What I end up is with an array containing many duplicate of the same template URL, where as the code should prevent duplicate from happening.
For context, the calls are made this way. Multiple calls within a few ms of each others:
await Tpl.loadFile(chrome.runtime.getURL("view/widget.html"));
let content = Tpl.render();
The output will look something like:
Fetching...
Fetching...
Fetching...
Fetching...
Fetching...
content
content
content
content
content
Instead of:
Fetching...
content
Cached!
Cached!
Cached!
Cached!
If I could have the entire LoadFile function executed just once at the time it would solve my problem.
Thank you !
2
Answers
Try to implement a simple locking mechanism.
With that you can be sure if there’s an ongoing fetch operation for a specific URL, so the calls for the same URL will wait until the first fetch is completed.
Here the example
The loop uses await new Promise(resolve => setTimeout(resolve, 10)) to periodically check the status….
The problem is that your caching system only works after the result has been received, but not while it still is loading. To fix this, store the promise itself in the cache, and store it immediately when starting the request.
Notice I also changed the function to return the (promise for the) content, not store it in some shared variable. Then call the function as follows:
Btw I’d also recommend to use a
Map
for thecache
instead of an array of objects.