0

Background

I am making a request every 5 seconds using XMLHttpRequest and I want to print my name when I receive the response.

To do this I am using onreadystatechange which allows me to define a callback function when I receive the answer.

Problem

To achieve this, I am using a class. When I first initiate the class I say my name immediately, and then I start a process using setTimeInterval to make a request every 5 seconds and see my name.

The problem is that I see my name the first time, but then I never see it again. The issue is that this seems to be in different context, and thus this.sayMyName() doesn't exist because it doesn't belong to the xhr object.

What I tried

To fix this I tried using scoping by following another StackOverflow question but unfortunately this remains undefined.

Code

class Cook {

    constructor() {
        // innitial call so we don't have to wait 
        //5 seconds until we see my name
        this.getCookInfo(); 

        setInterval(this.getCookInfo, 5000);
    }

    getCookInfo() {

        var xhr = new XMLHttpRequest(),
            method = "GET",
            url = "https://best.cooks.in.the.world.org/";

        xhr.open(method, url, true);

        //Call a function when the state changes.    
        xhr.onreadystatechange = (self => {
            return () => {
                if (xhr.readyState == XMLHttpRequest.DONE && xhr.status == 200)
                    self.sayMyName();
            };
        })(this);
    }

    sayMyName() {
        console.log("Heisenberg");
    }
}

Questions:

  1. Is there a way to fix this code without have to pass a context object to the setInterval function?

Note Kudos++ for those of you who get my reference :P

Community
  • 1
  • 1
Flame_Phoenix
  • 16,489
  • 37
  • 131
  • 266
  • 1
    pass `this.getCookInfo.bind(this)` to `setInterval` - or add `this.getCookInfo = this.getCookInfo.bind(this)` prior to the `setInterval` code – Jaromanda X Feb 01 '17 at 08:33
  • and, if you're using `class` you must have a modern browser ... so use `xhr.onload` instead of the 20th century `xhr.onreadystatechange` :p then you only have to check for `xhr.status`, not `xhr.readyState` as well – Jaromanda X Feb 01 '17 at 08:37
  • What about the closure, should I leave it? – Flame_Phoenix Feb 01 '17 at 08:40
  • I've posted an answer - no, you don't need the `IIFE` any more, because `this` will be the correct `this`, even inside the callback as you are using => function – Jaromanda X Feb 01 '17 at 08:42
  • you also seem to not have an `xhr.send()` - without which the request is never sent – Jaromanda X Feb 01 '17 at 08:44

1 Answers1

1

bind the this.getCookInfo function to this

then you can rally simplify your code

class Cook {

    constructor() {
        // innitial call so we don't have to wait 
        //5 seconds until we see my name
        this.getCookInfo(); 

        setInterval(this.getCookInfo.bind(this), 5000);
    }

    getCookInfo() {

        var xhr = new XMLHttpRequest(),
            method = "GET",
            url = "https://best.cooks.in.the.world.org/";

        xhr.open(method, url, true);

        //Call a function when the state changes.    
        // no need for self gymnastics any more
        // using onload, no need to test reasyState either
        xhr.onload = e => {
            if (xhr.status == 200)
                this.sayMyName();
        };
        // your code lacks one thing
        xhr.send();
    }

    sayMyName() {
        console.log("Heisenberg");
    }
}

An alternative -

class Cook {

    constructor() {
        this.getCookInfo(); 
    }

    getCookInfo() {
        var getit = () => {
            var xhr = new XMLHttpRequest(),
                method = "GET",
                url = "https://best.cooks.in.the.world.org/";

            xhr.open(method, url, true);

            //Call a function when the state changes.    
            xhr.onload = e => {
                if (xhr.readyState == XMLHttpRequest.DONE && xhr.status == 200)
                    this.sayMyName();
            };
            xhr.send();
        };
        getit();
        setInterval(getit, 5000);
    }

    sayMyName() {
        console.log("Heisenberg");
    }
}

I'm only 99% sure this is right though :p

Jaromanda X
  • 53,868
  • 5
  • 73
  • 87