Reputation: 95
I have to add a list of data structures to a js object on an HTML page.
I have a list of data structures on the server side each identified by a data-key
.
A js function loops the list of data-keys
the function gets each structure one at a time from a async_cache
using the corresponding data-key
.
There may be multiples of same data-keys
in the list
async_cache
doesn't have the data-structure
by that data-key
it async-fetches and adds it to the cache.async_cache
has the data-structure
by that data-key
it returns it right away.async_cache
has already requested a fetch for a data-key
and before the data arrives has another request for the same data-key
it must not duplicate the request but wait until the data arrives.I have constructed the following code so far (as an example for discussion). The actual environment can't be shared.
<?php
switch($_GET['--action'] ?? false){
case 'data-structure':{
$data_group = [
'data-01' => ['a' => 'info-01', 'b' => 'extra-01'],
'data-02' => ['a' => 'info-02', 'b' => 'extra-02'],
'data-03' => ['a' => 'info-03', 'b' => 'extra-03'],
'data-04' => ['a' => 'info-04', 'b' => 'extra-04'],
'data-05' => ['a' => 'info-05', 'b' => 'extra-05'],
];
if($data_struct = ($data_group[$_GET['key'] ?? false] ?? false)){
\header('Content-Type: application/json');
echo json_encode(['status'=> 'ok', 'data' => $data_struct], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
exit();
} else {
http_response_code(404);
echo json_encode('Not Found', JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
exit();
}
} break;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta key="viewport" content="width=device-width, initial-scale=1.0">
<title>JS Async Data Buffer Experiment</title>
</head>
<body>
<div class="container">
</div>
<script>
xui = {};
xui.async_cache = {
async async_get_await(url = '', options = {}){
// Default options are marked with *
const response = await fetch(
url,
{
method: 'GET', // *GET, POST, PUT, DELETE, etc.
mode: options.mode || 'same-origin', // no-cors, *cors, same-origin
cache: options.cache || 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: options.credintials || 'same-origin', // include, *same-origin, omit
redirect: options.redirect || 'follow', // manual, *follow, error
referrerPolicy: options.referrerPolicy || 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
}
);
return response.json(); // parses JSON response into native JavaScript objects;
},
get(action, key){
if(key in this){
return new Promise((resolve, reject) => {
resolve(this[key]);
});
} else {
return this.async_get_await(
`?--action=${action}&key=${key}`,
).then((r) => {
this[key] = r.data;
return this[key];
});
}
},
};
window.addEventListener('DOMContentLoaded', function(){
var list = [
'data-01',
'data-01',
'data-02',
'data-01',
'data-03',
'data-02',
'data-04',
'data-02',
'data-01',
];
list.forEach((key) => {
console.log({key});
xui.async_cache.get('data-structure', key).then((data) => {
console.log(data);
});
});
});
</script>
</body>
</html>
Case 1 and 2 are taken care of but case 3 is where I am stuck. As you can see the code in the addEventListner
executes in one shot before the data is received or event-loop kicks-in. So multiple requests go out for the same data-key
.
I am looking for a minimalist approach. If there is a coding feature in JS library without using third party library - that will do as well.
I've also looked into the cache option on the Fetch-API
but that is not a solution.
Thanks!
Upvotes: 0
Views: 337
Reputation: 95
Thanks to @Bergi I finally figured it out! I rewrote the async_cache and went on simplifying ... Here is what I got (I've added a few test buttons as well):
<?php
switch($_GET['--action'] ?? false){
case 'data-structure':{
$data_group = [
'data-01' => ['a' => 'info-01', 'b' => 'extra-01'],
'data-02' => ['a' => 'info-02', 'b' => 'extra-02'],
'data-03' => ['a' => 'info-03', 'b' => 'extra-03'],
'data-04' => ['a' => 'info-04', 'b' => 'extra-04'],
'data-05' => ['a' => 'info-05', 'b' => 'extra-05'],
];
if($data_struct = ($data_group[$_GET['key'] ?? false] ?? false)){
\header('Content-Type: application/json');
echo json_encode(['status'=> 'ok', 'data' => $data_struct], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
exit();
} else {
http_response_code(404);
echo json_encode('Not Found', JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
exit();
}
} break;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta key="viewport" content="width=device-width, initial-scale=1.0">
<title>JS Async Data Cache Example</title>
</head>
<body>
<div class="container">
<button type="button" onclick="run()">Run</button> <br/>
<button type="button" onclick="delete xui.async_cache['data-01']">Delete 01</button> <br/>
<button type="button" onclick="delete xui.async_cache['data-02']">Delete 02</button> <br/>
<button type="button" onclick="delete xui.async_cache['data-03']">Delete 03</button> <br/>
<button type="button" onclick="delete xui.async_cache['data-04']">Delete 04</button> <br/>
Look at the console for responses and check the network tab as well!
</div>
<script>
xui = {};
xui.async_cache = {
get(key){
return this[key] ?? (this[key] = (fetch(`?--action=data-structure&key=${key}`).then((response) => {
return response.json();
})));
}
};
function run(){
var list = [
'data-01',
'data-01',
'data-02',
'data-01',
'data-03',
'data-02',
'data-04',
'data-02',
'data-01',
];
list.forEach((key) => {
console.log({key});
xui.async_cache.get(key).then((data) => {
console.log(data);
});
});
}
window.addEventListener('DOMContentLoaded', function(){
run();
});
</script>
</body>
</html>
Looks like we can take advantage of the closure's data storage (or caching) inside the promise. And we don't need await or async, atleast for this rudimentary stage.
Upvotes: 1