0

I just started to work with hard part of JS, may be I couldn't find right question to search, but it would be understandable if I will show.

So in my code I want to make the variable "str" (which is global variable) equal to an element from "addEventListener" function which element should be "this.responseText".

var str = "initial";    
xhr.addEventListener("readystatechange", function () {      
    if (this.readyState === this.DONE) {
        str = this.responseText;
    }       
});

if(str != "initial"){
//do something
}

In function str (which equals "this.responseText") shows a text but when I want to see in out of function it shows undefined. So I expect str as sn inside of function

  • You're asking about 'event delegation'. – Obsidian Age Oct 29 '19 at 00:04
  • It's not really clear what you want to accomplish. Can you rephrase an write about what your end goal is and what both of the examples have to do with it? – Daniel Habenicht Oct 29 '19 at 00:07
  • see https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call/14220323#14220323 - surprised this hasn't been closed as duplicate – Bravo Oct 29 '19 at 00:16

2 Answers2

0

You must do it this way.

var str;    
xhr.addEventListener("readystatechange", function () {      
    if (this.readyState === this.DONE) {
        str = this.responseText; 
        document.getElementById("result").innerHTML = str;
    }       
});
Kelvin Mariano
  • 991
  • 8
  • 15
0
var str;    

// [1] Since event handling is asynchronous in JS, the event handler
// function 'handleReadyStateChange' will execute and return a result
// at an unpredicted time sometime in the future. 
// Since it is asynchronous, it will not block subsequent code [2] 
// but instead pass the execution step to that line.

xhr.addEventListener("readystatechange", function handleReadyStateChange() {      
    if (this.readyState === this.DONE) {
        str = this.responseText;
    }       
});

// [2] This line will execute immediately after [1] while [1] is STILL 
// at work and has not yet finished its operations.

document.getElementById("result").innerHTML = str;

I think it helps to see your code like this:

var str; // At this point, the value of str is 'undefined'

// This line will ALWAYS execute first, and thus pass the value
// 'undefined' to innerHTML.
// That's why I've placed this line before the xhr code.

document.getElementById("result").innerHTML = str;

// At some point, the callback function will execute and 
// pass the responseText to str subsequently to innerHTML

xhr.addEventListener("readystatechange", function handleReadyStateChange() {      
    if (this.readyState === this.DONE) {
        str = this.responseText;
        document.getElementById("result").innerHTML = str;
    }       
});

Bottom line is, that in asynchronous operations (like event handling, fetch() operations, setTimeout, etc.), your only option is to place the code that depends on the result of the asynchronous operation, inside a callback function (or a then() in the case of Promise-based asynchronous commands).

This is just a short intro to a great chapter in JavaScript called asynchronous programming. I suggest you rethink about your code again and then head over to the article pointed by @Bravo: How do I return the response from an asynchronous call?

And, speaking of chapters, here's a great one that dives into Asynchronous Programming in full detail: https://eloquentjavascript.net/11_async.html

Kostas Minaidis
  • 4,681
  • 3
  • 17
  • 25