/    Sign up×
Community /Pin to ProfileBookmark

Preload initial data and store into localStorage?

I have noticed that the “hen and egg” problem will occur now and then using Javascript. If I load a stored menu by fetch, I often cannot use this menu until it is “finished”. And **async** will make it more unpredictable as the load time is different.

My intention is to fetch a menu from database and then serve it **dynamically** from the menus in localStorage. But I must be sure that localStore is ready to use.

Is it possible to preload data ONCE and use this stored data in a predictable way?

https://jsfiddle.net/kmpfyswt/1/

to post a comment
JavaScript

17 Comments(s)

Copy linkTweet thisAlerts:
@SempervivumDec 06.2022 — Ajax is predictable when handled properly.

When using `then</C>, <C>async</C> and <C>await</C> are not necessary and, the other way round, when using <C>async</C> and <C>await</C>, <C>then</C> is not necessary.

The main thing that has been adhered to is, that the response from the server is available only in the <C>
then</C> callback or inside the <C>async</C> function.<br/>
That's the reason why your code is not working reliably.<br/>
This should:
<CODE>
`<i>
</i>fetch(url)
.then(response =&gt; response.json())
.then(data =&gt; {
localStorage.setItem('main', data);
// do anything you like with data here
});
// In this place data being stored in local storage
// will not be available reliably<i>
</i>
``
Copy linkTweet thisAlerts:
@sibertauthorDec 06.2022 — > @Sempervivum#1649027 Ajax is predictable when handled properly.

Javascript is still a challenge for me... :-)

But your suggestion seems to work. Thank You!

https://jsfiddle.net/xyod13Lj/1/
Copy linkTweet thisAlerts:
@SempervivumDec 06.2022 — I'm afraid that this will not work reliably when the response is not cached and/or data is large or the server is not that fast. Note my remarks:
>// In this place data being stored in local storage

// will not be available reliably
Copy linkTweet thisAlerts:
@sibertauthorDec 06.2022 — > @Sempervivum#1649033 // In this place data being stored in local storage

> // will not be available reliably


Do I interpret this that it is not possible to fetch reliable OR do I miss something?
Copy linkTweet thisAlerts:
@SempervivumDec 06.2022 — You will have to perform **any** action that references the response from the server **inside** the `then` callback. When doing so, the data will be available reliably. Many developers wish to store the data in a variable or in local storage and access it later on from anywhere. This is not possible.
Copy linkTweet thisAlerts:
@sibertauthorDec 06.2022 — > @Sempervivum#1649035 You will have to perform any action that references the response from the server inside the then callback. When doing so, the data will be available reliably

How about this? The menu is within the then callback?

``<i>
</i>function get_menu() {
let url = "https://api3.go4webdev.org/main/std";
fetch(url)
.then(response =&gt; response.json())
.then(data =&gt; store(data));
}
get_menu()

function store(menu) {
localStorage.setItem('main', data)
}<i>
</i>
``
Copy linkTweet thisAlerts:
@SempervivumDec 06.2022 — Yes, but when you will try to access that entry in local storage outside the `then</C> callback, it will not be available reliably.

One option is storing the promise in a variable, this will be available anywhere in your code but will require <C>
then`
to access the data.
Copy linkTweet thisAlerts:
@SempervivumDec 06.2022 — I coded and tested this example:
``<i>
</i> function fetchIt() {
return fetch('thread1042-promise-sibert.php')
.then(response =&gt; response.text());
}
prom = fetchIt();
// The variable prom is containing a promise now:
console.log(prom);

// You can place the following code anywhere
// but will need "then" in order to access the data:
prom.then(txt =&gt; {
console.log(txt);
// Perform any actions with txt here
});<i>
</i>
``
Copy linkTweet thisAlerts:
@zerodhavsmstock2Dec 08.2022 — Due to their lack of delivery freights and cheap, flat trading freights(Rs. 20), Zerodha and M Stock are two of the most popular bargain brokers in India. Small quantities of plutocrat( Rs 20 each trade) can get you a lot of openings to make deals in bulk. To start, M Stock and Zerodha are identical in freights and features. Between [Zerodha vs M Stock](https://www.thebeststockbroker.com/zerodha-vs-m-stock/), Zerodha has further than 12 lakh guests and is the largest reduction broker.
Copy linkTweet thisAlerts:
@johniiDec 09.2022 — You can use localStorage to store data in the browser. You can use it in preload phase, load phase, and even the post load phase. What you need to be careful about is the performance of your website. Users will face performance issues if you constantly store and retrieve data from the server. Meta tags, which are short and simple text descriptions, can dramatically increase your chances of ranking well in search engines. But you need to find high quality and relevant tags to use for your webnsite, i mostly use [Redbubble tag generator](https://redbubbletools.com) for my websites tags
Copy linkTweet thisAlerts:
@sibertauthorDec 09.2022 — > @Sempervivum#1649039 One option is storing the promise in a variable, this will be available anywhere in your code but will require then to access the data.

I have still problems, but this is a bit on the journey. I think that sessionStore will be more useful than localStorage as it leaves no garbage on the users browser.

``<i>
</i>if (window.location.href.split("/").pop() === "") {
window.location.href = "home"
}

const load_menu = async () =&gt; {
try {
const response = await fetch('https://api3.go4webdev.org/menu/all')
const data = await response.json()
sessionStorage.setItem('main', JSON.stringify(data));
} catch (err) {
console.error(err)
}
}

const get_menu = async () =&gt; {
if (sessionStorage.main == null) {
await load_menu()
}
let data = JSON.parse(sessionStorage.main)
let main = document.body.dataset.main
fillmain(data.filter(item =&gt; item.menu_main == ['min']))
fillsub(data.filter(item =&gt; item.menu_main == [main]))
}

get_menu()

//let fragment = new DocumentFragment() &lt;---does not work

//create menus from database.
function fillmain(data) {
let mainlist = document.getElementById("mainlist");
data.forEach(function(item) {
let li = document.createElement('li')
li.setAttribute('id', item.menu_id)
li.innerHTML =
<a href=" + item.menu_lnk + "><svg class="icn56"><use xlink:href=" + item.menu_icn + "/></svg><span> + item.menu_txt + </span></a>
mainlist.appendChild(li)
})
// mainlist.appendChild(fragment) //does not work...
}

function fillsub(data) {
let sublist = document.getElementById("sublist");
data.forEach(function(item) {
sublist.setAttribute('data-main', item.menu_main)
let li = document.createElement('li')
li.setAttribute('id', item.menu_id)
li.innerHTML =
<a href=" + item.menu_lnk + "> + item.menu_txt + </a>
sublist.appendChild(li)
})
// mainlist.appendChild(fragment)
}

// the last piece is to select the current selection in menu based on window.location.href

let mainli = document.querySelectorAll("#mainlist li")
let subli = document.querySelectorAll("#sublist li");
let main = document.body.dataset.main
let localhref = window.location.href.split("/").pop()

select()

function select() {
subli.forEach(function list(item) {
let href = item.firstElementChild.href.split("/").pop()
if (href === localhref) {
item.classList.add("selected")
}
});

mainli.forEach(item =&gt; {
let sub = item.id
if (sub === main) {
item.classList.add("selected");
}
});
}<i>
</i>
``

Live: https://nav.go4webdev.org

There is still at least 2 problems left:

  • 1. The current menu items is not selected FIRST time when loaded from the database. It may reduce the flickering further?

  • 2. I cannot use fragment when creating the ul lists. Why?


  • Any clue why fragment and selecting is failing?
    Copy linkTweet thisAlerts:
    @SempervivumDec 12.2022 — It's always the same issue: Any action that's based on the response of the server has to be done inside the `then</C> callback or the async function:
    <CODE>
    `<i>
    </i>const get_menu = async () =&gt; {
    if (sessionStorage.main == null) {
    await load_menu()
    }
    let data = JSON.parse(sessionStorage.main)
    let main = document.body.dataset.main
    fillmain(data.filter(item =&gt; item.menu_main == ['min']))
    fillsub(data.filter(item =&gt; item.menu_main == [main]))
    // The menu items are ready here
    // Highlight the current item:
    select();
    }<i>
    </i>
    `</CODE>
    The following code is located outside the async function, therefore the menu items are not available reliably here, as they are created only when the response of the server has arrived:
    <CODE>
    `<i>
    </i>let mainli = document.querySelectorAll("#mainlist li")
    let subli = document.querySelectorAll("#sublist li");
    let main = document.body.dataset.main
    let localhref = window.location.href.split("/").pop()

    // select()<i>
    </i>
    ``
    Copy linkTweet thisAlerts:
    @sibertauthorDec 12.2022 — > @Sempervivum#1649159 It's always the same issue:

    Soon I maybe get this :-) But how about select while creating the menus? Then I get rid of som lines of code for selecting...

    ``<i>
    </i>function fillmain(data) {
    let mainlist = document.getElementById("mainlist");
    let main = document.body.dataset.main
    data.forEach(function(item) {
    let li = document.createElement('li')
    li.setAttribute('id', item.menu_id)
    if (item.menu_id === main) {
    li.classList.add("selected") &lt;----- select when loading :-)
    }
    li.innerHTML =
    <a href=" + item.menu_lnk + "><svg class="icn56"><use xlink:href=" + item.menu_icn + "/></svg><span> + item.menu_txt + </span></a>
    mainlist.appendChild(li)
    })
    }<i>
    </i>
    ``

    live: https://nav.go4webdev.org
    Copy linkTweet thisAlerts:
    @SempervivumDec 12.2022 — Yeah, this is possible.

    Additionally I looked into your code deeper and got the expression that it could be simplified:
    ``<i>
    </i> async function makeMenu() {
    const response = await fetch('https://api3.go4webdev.org/menu/all');
    const data = await response.json();
    const main = document.body.dataset.main;
    fillmain(data.filter(item =&gt; item.menu_main == ['min']));
    fillsub(data.filter(item =&gt; item.menu_main == [main]));
    select(); // This may get obsolete by your latest proposal
    }

    makeMenu()<i>
    </i>
    ``

    No storage needed, easy to code, easy to read, easy to maintain and extend.
    Copy linkTweet thisAlerts:
    @sibertauthorDec 12.2022 — > @Sempervivum#1649162 No storage needed

    I have been told that every trip to the database is more or less expensive. So storing the menu in a sessionStorage is a way to achieve less traffic to the server and api. And memory is way faster than serve via an API. Causing mor flickering etc. What do you think?
    Copy linkTweet thisAlerts:
    @SempervivumDec 12.2022 — The browser will save the result of the fetch in it's cache which will have the same effect as storing it in local storage.
    Copy linkTweet thisAlerts:
    @sibertauthorDec 12.2022 — > @Sempervivum#1649164 The browser will save the result of the fetch in it's cache

    So there will be NO traffic to the API and the server?
    ×

    Success!

    Help @sibert spread the word by sharing this article on Twitter...

    Tweet This
    Sign in
    Forgot password?
    Sign in with TwitchSign in with GithubCreate Account
    about: ({
    version: 0.1.9 BETA 4.19,
    whats_new: community page,
    up_next: more Davinci•003 tasks,
    coming_soon: events calendar,
    social: @webDeveloperHQ
    });

    legal: ({
    terms: of use,
    privacy: policy
    });
    changelog: (
    version: 0.1.9,
    notes: added community page

    version: 0.1.8,
    notes: added Davinci•003

    version: 0.1.7,
    notes: upvote answers to bounties

    version: 0.1.6,
    notes: article editor refresh
    )...
    recent_tips: (
    tipper: @Yussuf4331,
    tipped: article
    amount: 1000 SATS,

    tipper: @darkwebsites540,
    tipped: article
    amount: 10 SATS,

    tipper: @Samric24,
    tipped: article
    amount: 1000 SATS,
    )...