【问题标题】:Promise not returning value of request承诺不返回请求的值
【发布时间】:2018-04-10 15:39:06
【问题描述】:

我有这个承诺:

function getAPI(token)
{
return new Promise((resolve, reject) => {
    console.log("Request API");
    GM_xmlhttpRequest({
        method: "GET",
        url: "URL"+token,
        onload: function(response) {
            console.log(response.responseText);
            if( response.responseText == "NOT_ANSWER" || response.responseText.indexOf("ERRO") > -1 ){
                console.log(response.responseText + " - Calling Myself in 5 Seconds");
                setTimeout(function(){
                    getAPI(token);
                },5000);
            }
            else{
                console.log('Call API - Giving Result');
                resolve(response.responseText.split("_")[1]);
            }
        }
    });
});

}

当答案不是我想要的,但不能少于 5 秒时,我会在内部调用它。

然后我在主函数中这样做:

setTimeout( function(){
                getAPI(token).then((key) => {
                    console.log(key);
                    doSomethingWithKey;
                    setTimeout( function(){
                        loop();
                    },1000);
                }).catch(() => {
                    console.log('Error na api - reload page!');
                    location.reload();
                });
            },25000);

但我注意到,当 getAPI 调用自身时,导致答案不是我想要的,主函数中的“.then”永远不会执行,我的代码挂在那里。我该如何解决?我不太了解承诺,但我不明白为什么它会挂起......

【问题讨论】:

    标签: javascript promise request tampermonkey gm-xmlhttprequest


    【解决方案1】:

    当答案不是我想要的时,我会在其内部调用它,

    然后你不调用你从顶部 getAPI 调用返回的承诺的 resolve,所以承诺永远不会解决,你的 then 回调永远不会得到任何结果。

    你应该 promisify 你的异步函数 GM_xmlhttpRequestsetTimeout 在最低级别,然后只链接你的承诺。通过returning 来自then 回调的递归调用的结果,生成的promise 将以相同的结果解析:

    function xhrAsync(url) {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: "GET",
                url: url,
                onload: resolve
            });
        });
    }
    function delayAsync(time) {
        return new Promise(resolve => {
            setTimeout(resolve, time);
        });
    }
    function getAPI(token) {
        console.log("Request API");
        return xhrAsync("URL"+token).then(response => {
    //  ^^^^^^                       ^^^^
            console.log(response.responseText);
            if (response.responseText == "NOT_ANSWER" || response.responseText.includes("ERRO")) {
                console.log(response.responseText + " - Calling Myself in 5 Seconds");
                return delayAsync(5000).then(() => {
    //          ^^^^^^                  ^^^^
                    return getAPI(token);
    //              ^^^^^^
                });
            } else {
                console.log('Call API - Giving Result');
                return response.responseText.split("_")[1];
            }
        });
    }
    

    【讨论】:

    • 我认为你的答案也适用,尽管另一个对我来说更容易实现。
    • 是的,它需要进行更多更改,但它是一种更清洁、更安全的解决方案。通过在任何地方使用 Promise,您可以获得它们的好处,例如错误恢复等。如果您喜欢它,您仍然可以在接受其他答案的同时对其进行投票 :-)
    • 我实际上不得不使用您的解决方案,并且效果更好。一个问题。假设我在执行此调用之前设置了超时,突然间我超时了,我想取消所有超时和正在此处完成的调用。在调用 getAPI 的函数中调用“第一个”超时也会取消内部的所有超时或不取消?
    【解决方案2】:

    您正在创建多个 Promise,因为每次调用 getAPI 都会创建并返回一个 new Promise。

    getAPI 不应该调用自己(或者如果调用,它应该将新的承诺传递给resolve);相反,只需重试其中需要重试的部分,如下所示:

    function getAPI(token) {
        return new Promise((resolve, reject) => {
            // Function to do the request
            function doRequest() {
                console.log("Request API");
                GM_xmlhttpRequest({
                    method: "GET",
                    url: "URL" + token,
                    onload: function(response) {
                        console.log(response.responseText);
                        if (response.responseText == "NOT_ANSWER" || response.responseText.indexOf("ERRO") > -1) {
                            // Not what we wanted, retry
                            console.log(response.responseText + " - Calling Myself in 5 Seconds");
                            setTimeout(doRequest, 5000);
                        }
                        else {
                            console.log('Call API - Giving Result');
                            resolve(response.responseText.split("_")[1]);
                        }
                    }
                });
            }
            doRequest();
        });
    }
    

    旁注:您使用 getAPI 的代码正在检查承诺拒绝,但 getAPI 中没有任何内容拒绝承诺。

    【讨论】:

    • 我会试试的。确实,你是对的,我仍然需要弄清楚要在那里捕捉什么,因为当我得到我不想要的东西时,我想再次调用它,我将删除 catch tbh。我现在明白你的意思了,我需要解决新的 getAPI 调用,所以当我得到正确的答案时,它会递归地将解决方案发送给“向后”创建的每个承诺,并最终给我想要的结果。对吗?
    • 顺便说一句,它是 'setTimeout(doRequest, 5000);'或'setTimeout(function(){doRequest}, 5000);' ?当我使用第一种情况时,有时会出现奇怪的行为......
    • 工作。非常感谢O我没弄明白
    • @PedroOliveira:您遇到的setTimeout(doRequest, ...)setTimeout(function() { doRequest(); }, ...) 的问题可能与调用中的this(与doReques 无关)或传递给的参数有关功能。例如,setTimeout(obj.method, 5000);setTimeout(function() { obj.method(); }, 5000); 之间存在很大差异,更多的是 in this question's answers
    猜你喜欢
    • 2019-01-13
    • 2017-05-15
    • 2017-02-22
    • 1970-01-01
    • 1970-01-01
    • 2015-10-30
    • 1970-01-01
    • 1970-01-01
    • 2014-10-31
    相关资源
    最近更新 更多