XMLHttpRequest.onreadystatechange的上下文问题

时间:2017-02-01 08:31:11

标签: javascript ajax xmlhttprequest this setinterval

背景

我使用XMLHttpRequest每5秒发出一次请求,我想在收到回复时打印我的名字。

要做到这一点,我使用的是onreadystatechange,它允许我在收到答案时定义一个回调函数。

问题

为了达到这个目的,我正在上课。当我第一次开始上课时,我立刻说出了我的名字,然后我开始使用setTimeInterval每隔5秒发出一个请求并看到我的名字。

问题是我第一次看到我的名字,但后来我再也看不到了。问题是this似乎在不同的上下文中,因此this.sayMyName()不存在,因为它不属于xhr对象。

我尝试了什么

要解决此问题,我尝试使用另一个StackOverflow question进行范围设定,但不幸的是this仍未定义。

代码

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");
    }
}

问题:

  1. 有没有办法修复此代码而无需将上下文对象传递给setInterval函数?
  2. 注意 Kudos ++给那些得到我参考的人:P

1 个答案:

答案 0 :(得分:1)

this.getCookInfo函数绑定到this

然后你可以集中简化你的代码

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");
    }
}

替代方案 -

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");
    }
}

我只有99%确定这是正确的:p