Search code examples
javascriptgoogle-chrome-extensiongetxmlhttprequestmanifest.json

JAVASCRIPT WARNING: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience


I'm trying building a simple dictionary chrome extension. I found this API online Text from where I fetched (through an HTTP Request) a string consisting of word details and parsed the string into a JSON object. But when I use the extension, I get this warning regarding Synchronous XMLHttpRequest. I have provided the code below:

manifest.json


{
    "name": "Dictionary Extension",
    "version": "1.0",
    "description": "Finds the meaning of the word entered by user",
    "browser_action": {
        "default_title": "Hello there! What is it that you're looking for",
        "default_popup": "popup.html",
        "default_icon": {
          "16": "dic.png",
          "32": "dic.png"
        }
    },
    "content_scripts": [
      {
        "matches": ["<all_urls>"],
        "js": ["popup.js"]
      }
    ],
    "manifest_version": 2
}

<!--popup.js-->

var url = "https://api.dictionaryapi.dev/api/v2/entries/en_US"
var input = document.getElementById("input");
var button = document.getElementById("btn");
var mat = document.getElementById("material");

function httpGet(theUrl) {
  var xmlHttp = new XMLHttpRequest();
  xmlHttp.open("GET", theUrl, false); // false for synchronous request
  xmlHttp.send(null);
  return xmlHttp.responseText;
}



button.addEventListener("click", function() {
  mat.innerHTML = "";
  var val = input.value;
  var temp_url = url + "/" + val;
  var json_data = httpGet(temp_url);
  var data = JSON.parse(json_data);
  var l = data[0].meanings.length;
  for (var i = 0; i < l; i++) {
    var len = ((data[0].meanings[i]).definitions).length;
    part_of_speech = (data[0].meanings[i]).partOfSpeech;
    var h1 = document.createElement("h2");
    var list = document.createElement("ol");
    h1.innerHTML = part_of_speech;
    mat.appendChild(h1);

    for (var j = 0; j < len; j++) {
      var def = (data[0].meanings[i]).definitions[j].definition;
      var li = document.createElement("li");
      li.innerHTML = def;
      list.appendChild(li);
    }
    mat.appendChild(list);
  }
});
<!--popup.html-->

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Find Meaning</title>
</head>

<body>
  <h1>Hello there! What is it that you're looking for?</h1>
  <label for="word">Enter the word</label>
  <input id="input" type="text" placeholder="Word">
  <button id="btn">Find Meaning</button>

  <div id="material"></div>

  <script src="popup.js"></script>
</body>

</html>

Here's what I've tried. I tried changing the 'async' parameter of the function XMLHttpRequestObject.open() to true but then, it gave the following error: Uncaught SyntaxError: Unexpected end of JSON input. I searched about this, and came to conclusion that, the function httpGet() is returning the string much later and during that time, the function on the click event of the button is executed. So, now "data" variable is "undefined" because the value from httpGet has not been returned yet. Thus, it can't parse undefined into a json object. I'm new to Js and don't know much about HTTP. Any help on this would be really appreciated.


Solution

  • Look into async/await and promises, but the basic changes you need to make are:

    button.addEventListener("click", async function() {
        // ...
        var json_data = await httpGet(temp_url);
        // ...
    })
    
    function httpGet(theUrl) {
      return new Promise((resolve, reject) => {
        var xmlHttp = new XMLHttpRequest();
        xmlHttp.onload = function () {
            if (this.status >= 200 && this.status < 300) {
                resolve(xmlHttp.response);
            } else {
                reject({
                    status: this.status,
                    statusText: xmlHttp.statusText
                });
            }
        };
        xmlHttp.open("GET", theUrl, true); // true for asynchronous request
        xmlHttp.send(null);
      });
    }