Search code examples
javascriptasync-awaitfetch

Async-await fetch call triggers duplicate alerts


I've created an editor with JS and PHP to allow text and image changes on a webpage. Consider the following JS function:

const publish = () => {

    if (unpublished || Object.keys(files).length) {

        // start spinning loader
        let icon = document.getElementById("loader");
        icon.innerText = 'refresh';
        icon.classList.add("spin");

        // text changes
        if (unpublished) {
            let parcel = new FormData();
            parcel.append("lang", langId);
            parcel.append("page", pageId);
            parcel.append("edits", JSON.stringify(edits));

            send(parcel);

            unpublished = false;
        }

        // image changes
        if (Object.keys(files).length) {

            Object.keys(files).forEach(section => {
                const length = Object.keys(files[section]).length;
                for (let i = 0; i < length; i++) {

                    const tag = Object.keys(files[section])[i];
                    const file = Object.values(files[section])[i];
                    let parcel = new FormData();
                    parcel.append("lang", langId);
                    parcel.append("page", pageId);
                    parcel.append("section", section);
                    parcel.append(tag, file);

                    send(parcel);
                }
            })
            files = {};
        }

        async function send(parcel) {
            const response = await fetch("", {
                method: "POST",
                body: parcel,
            });
            if (!response.ok) alert(Error(response.statusText));
            if (!unpublished && !Object.keys(files).length) {

                // stop spinning loader
                icon.classList.remove("spin");
                icon.innerText = 'save';
                alert("changes published");
            }
        }
    }
}

The changes (parcel) are processed with PHP. Everything works fine if the user changes either text or an image. However, if both are changed, the 'changes published' alert is triggered twice, even though the condition

if (!unpublished && !Object.keys(files).length)

shouldn't be true until after

files = {};


Solution

  • @Bergi Thanks, it's working now. Below is the result in case anyone needs it:

    const publish = () => {
    
    if (Object.keys(edits).length || Object.keys(files).length) {
    
        let promises = [];
    
        // start spinning loader
        let icon = document.getElementById("loader");
        icon.innerText = 'refresh';
        icon.classList.add("spin");
    
        // text changes
        if (Object.keys(edits).length) {
            let parcel = new FormData();
            parcel.append("lang", langId);
            parcel.append("page", pageId);
            parcel.append("edits", JSON.stringify(edits));
    
            promises.push(send(parcel));
    
            edits = {};
        }
    
        // image changes
        if (Object.keys(files).length) {
    
            Object.keys(files).forEach(section => {
                const length = Object.keys(files[section]).length;
                for (let i = 0; i < length; i++) {
    
                    const tag = Object.keys(files[section])[i];
                    const file = Object.values(files[section])[i];
                    let parcel = new FormData();
                    parcel.append("lang", langId);
                    parcel.append("page", pageId);
                    parcel.append("section", section);
                    parcel.append(tag, file);
    
                    promises.push(send(parcel));
                }
            })
    
            files = {};
        }
    
        // send parcel
        async function send(parcel) {
            const response = await fetch("", {
                method: "POST",
                body: parcel,
            });
            if (!response.ok) alert(Error(response.statusText));
        }
    
        Promise.all(promises).then(() => {
    
            // stop spinning loader
            icon.classList.remove("spin");
            icon.innerText = 'save';
            alert("changes published");
            return;
        })
    }
    

    }