Search code examples
javascriptasynchronousxmlhttprequestaddeventlistener

Stop click EventListener synchronous behaviour when calling web service after button click


I have a review popup which when closed using the x button should close itself and then call a XMLHttpRequest to call a web service for updating some feedback info.

The issue I have is that when the button is clicked the window popup does not close instantly but seems to wait for the XMLHttpRequest to return 200. Is this due to "EventListener" behaviour or the "XMLHttpRequest"?

I should probably mention that I am specifically making XMLHttpRequest synchronous via the "false" param in xmlHttp.open( "GET", URL, false ); as this seems to be required as when the request is async eg: xmlHttp.open( "GET", URL, true); the if (xmlHttp.status === 200) doesn't run and is required for setting a global variable needed down the line.

I have added my code below.

Is there a way for my feedbackPopup() function to close the popup window without waiting for the web service 200? I need the window close to be instant.

Sorry if im making a silly mistake somewhere, still learning.

Thank you in advance for any help.

//used for running closeFeedback Logic

var close = document.getElementById('closeOverlay');
  close.addEventListener('click', closeFeedback);
  
  
  
function updateFeedback(a, b, c){

  const host = window.location.host;
  let URL = 'someURL${a}${b}${c}'

  var xmlHttp = new XMLHttpRequest();
  xmlHttp.open( "GET", URL, false ); // false for synchronous request
  xmlHttp.send( null );

  if (xmlHttp.status === 200){
  // this is not set for future use if line 14 is set to true 
    SomeGlobal = b;
  }else{
    console.log("xmlHttp.status","",xmlHttp.status)
  }

 }
 
 //this is used for both opening and closing the popup which is why the conditional operator is used
 function feedbackPopup() {
  el = document.getElementById("feedback");
  el.style.visibility = (el.style.visibility == "visible") ? "hidden" : "visible";


}



//should close feedback and call web service function 
function closeFeedback(){

//ISSUE : this closeFeedbackWindow should close the window before updateFeedback runs and should not wait for updateFeedback to retunr 200???
  feedbackPopup();

  updateFeedback(a, b, c);
  
  
  ...
  //More logic here which uses the SomeGlobal variable set in updateFeedback


}


Solution

  • As JaromandaX said, the problem is that you're making a synchronous ajax request. That locks up the UI of the browser (at least that tab, in some browsers worse than that) while the network operation is running. Let the request default to being asynchronous instead. (Synchronous requests may even stop working someday.)

    this is not set for future use if line 14 is set to true

    That's only because you're not handling the request correctly. To handle an asynchronous request, use onload and onerror (or onreadystatechange for more detail); more in MDN's documentation. And since you have further logic after the call to updateFeedback, you need to (if we're doing to do this the old-fashioned way) add a callback to it:

    function updateFeedback(a, b, c, callback) {
        const host = window.location.host;
        let URL = 'someURL${a}${b}${c}'
    
        var xmlHttp = new XMLHttpRequest();
        xmlHttp.onload = () => {
            SomeGlobal = b;
            callback(true); // Worked
        };
        xmlHttp.onerror = () => {
            console.log("xmlHttp.status", "", xmlHttp.status)
            callback(false); // Didn't work
        };
        xmlHttp.open("GET", URL);
        xmlHttp.send(null);
    }
    

    The the call to it becomes:

    updateFeedback(a, b, c, (success) => {
        //More logic here which uses the SomeGlobal variable set in updateFeedback
    });
    

    Or better yet, use fetch, the modern standard replacement for XMLHttpResponse, and make updateFeedback return a promise:

    function updateFeedback(a, b, c) {
        const host = window.location.host;
        let URL = 'someURL${a}${b}${c}'
    
        fetch(URL)
        .then((response) => {
            if (response.ok) {
                SomeGlobal = b;
            } else {
                throw new Error(`HTTP error, status = ${response.status}`);
            }
        })
        .error((error) => {
            console.log(error.message ?? error);
        });
    }