【问题标题】:Calling Resolve function goes to Reject function in JavaScript Promise调用 Resolve 函数转到 JavaScript Promise 中的 Reject 函数
【发布时间】:2016-12-09 07:56:23
【问题描述】:

我有以下代码:

return new Promise (function (resolve,reject) {
        if (this.ImageData && averageColor) {
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function () {
                if (xhr.readyState == XMLHttpRequest.DONE && xhr.status == 200) {
                    console.log("Image found");
                    resolve(xhr.response);
                }else {
                    console.log("Image not found");
                    reject();
                }
            }
            xhr.open('GET', 'http://localhost:8765/color/'+averageColor, true);
            xhr.send(null);
        }
        else {
            reject();
        }
    });

调用这段代码的函数如下:

var v =  tile.getImage(tile.getColorAverage());
        v.then(function (value) {
            console.log("laughing");
        }).catch(function () {
           console.log("Catch called");
        });

问题在于我的承诺,我可以看到它处于 if 条件并正确地从服务器获取响应(因为 console.log)。然而,另一方面,它根本没有进入“当时”的承诺(甚至一次都没有)。由于某种原因,它会被拒绝。我要疯了,因为我可以看到它执行了应该解决它的位,但那时我什么也没得到。任何帮助将不胜感激。

已编辑:

现在我只运行了一次。这是我的 console.log 跟踪。现在更加困惑:

【问题讨论】:

  • 您希望this 包含在Promise 解析器函数中吗?
  • 你能在两个拒绝呼叫之前放一个控制台.log - 只是为了调试

标签: javascript asynchronous promise


【解决方案1】:
xhr.onreadystatechange = function () {
    if (xhr.readyState == XMLHttpRequest.DONE && xhr.status == 200) {
        console.log(xhr.response);
        resolve(xhr.response);
    }else {
        reject();
    }
}

关于 onreadystatechange 的事情是,它被多次调用

关于promise解决的事情是一旦rejected或者resolved,就不能再rejected或者resovled了

第一次调用 onreadystatechange 时,状态将是 1,而不是 4 ...所以你拒绝

只有当 status 为 4 并且 (DONE) AND status != 200 时,您才应该拒绝

xhr.onreadystatechange = function () {
    if (xhr.readyState == XMLHttpRequest.DONE) {
        if(xhr.status == 200) {
            console.log(xhr.response);
            resolve(xhr.response);
        } else {
            reject();
        }
    }
}

或者,使用 onload/onerror - 尽管您仍然需要检查 onload 中的 status == 200

xhr.onload= function () {
    if(xhr.status == 200) {
        console.log(xhr.response);
        resolve(xhr.response);
    } else {
        reject();
    }
}


xhr.onerror= function () {
    reject();
}

作为一些有用但看起来不对的东西的旁注

return new Promise (function (resolve,reject) {
    if (this.ImageData && averageColor) {

promise 构造函数回调中的this 可以是window,甚至在严格模式下甚至可以是undefined - 您需要在它导致问题之前修复该代码

【讨论】:

  • load 事件替换readystatechange 事件应该可以解决问题,是吗?
  • 是的,但是 onerror 也应该被处理 - 并且 onload 仍然需要检查 stats == 200
  • 你没有在Promise构造函数中解决this的问题
  • 这不是问题的一部分,我什至没有展示那部分代码!您的回答没有解决关于 onreadystatechange 的错误假设 - 所以...
  • @guest271314 - 在严格模式下不会是窗口 - 所以你的假设是有缺陷的
【解决方案2】:

您遇到此问题的原因是 onreadystatechange 在请求完成之前被多次调用,在它完成之前,您将获得调用 rejectelse 条件。只有在DONE AND xhr.status != 200 时,您才应该拒绝。这是一个例子:

if (xhr.readyState == XMLHttpRequest.DONE) {
    if (xhr.status == 200) {
        resolve(xhr.response);
    } else {
        reject();
    }
}

【讨论】:

    【解决方案3】:

    Promise 构造函数中的thiswindow,除非专门设置为不同的值。 this.ImageData 将评估为 false 而不将 this 设置为在调用 new Promise() 时将 .ImageData 作为属性的对象。

    Promise 构造函数解析器函数中的 this.ImageData 替换对具有属性 ImageData 的对象的引用。

    例如

    function resolver(resolve, reject) {
    
    }
    
    new Promise(resolver.bind(/*object that has `.ImageData` as property*/))
    

    另外,用load 事件替换readystatechange 事件,并为XMLHttpRequest 对象包含error 事件处理程序。

    【讨论】:

    • 谢谢。那并不能解决问题。它在 onreadystatechange 函数中调用 resolve 函数(我可以通过 console.log 看到)。但是,它现在出现在 .then
    • @fur866 “但是,它现在显示在 .then 中” 不确定您的意思?
    • console.log(xhr.response); 被输出的事实意味着(无论多么被误导)如果条件为真 - 所以不应该调用拒绝
    • this 可能是 undefined - 在这种情况下不是,但假设它是 window 与原始代码所做的假设一样大
    • @JaromandaX 是的,你是对的。建议在答案中明确设置this。您的回答现在解决了这两个问题。
    猜你喜欢
    • 1970-01-01
    • 2017-11-09
    • 2019-12-14
    • 1970-01-01
    • 2018-10-10
    • 2019-01-20
    • 2021-11-05
    • 2019-04-07
    • 2019-09-15
    相关资源
    最近更新 更多