Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/413.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
javascript在返回承诺时遇到问题-返回的承诺未执行_Javascript_Winjs - Fatal编程技术网

javascript在返回承诺时遇到问题-返回的承诺未执行

javascript在返回承诺时遇到问题-返回的承诺未执行,javascript,winjs,Javascript,Winjs,我有一个像这样的函数 this.getToken = function() { if (token === null) { token = getAccessTokenAsync("username", "password"); lastTokenTime = getTokenExpiryAsync(); } } 此函数将调用getAccessTokenAsync,它将使用xhr向我的web服务器发出请求。这看起来像这样: getAccessTo

我有一个像这样的函数

this.getToken = function() {
    if (token === null) {
        token = getAccessTokenAsync("username", "password");
        lastTokenTime = getTokenExpiryAsync();
    }
}
此函数将调用getAccessTokenAsync,它将使用xhr向我的web服务器发出请求。这看起来像这样:

getAccessTokenAsync = function (username, password) {
    var serializedData = {
        username: username, password: password,
    };

    return new WinJS.Promise(function (complete) {
        WinJS.xhr({
            type: "post",
            url: "http://127.0.0.1:8080/authenticate/login",
            responseType: "json",
            data: JSON.stringify(serializedData)
        }).done(
            function complete(result){
                return JSON.parse(result.responseText);
            }
        );
    })
}
getAccessTokenAsync = function (username, password) {
    var serializedData = {
        username: username, password: password,
    };

    return WinJS.xhr({
            type: "post",
            url: "http://127.0.0.1:8080/authenticate/login",
            responseType: "json",
            data: JSON.stringify(serializedData)
        }).then(
            function complete(result){
                return JSON.parse(result.responseText);
            }
        );
    })
}
return new WinJS.Promise(function (completeDispatch) {  //Name the dispatcher for clarity
    WinJS.xhr({
        type: "post",
        url: "http://127.0.0.1:8080/authenticate/login",
        responseType: "json",
        data: JSON.stringify(serializedData)
    }).done(
        function (result) {  //Keep this anonymous for clarity
            completeDispatch(JSON.parse(result.responseText));
        }
    );
})
我希望token现在能在里面存储一个承诺。当我们调用
.done()
.next()
时,它将拥有服务器返回的json对象。但是,当我调用
getTokenExpiryAsync()
时,会发生其他事情

getTokenExpiryAsync = function () {
    if (token === null) {
        return new Date();
    }

    token.then(
        function complete(result){
            console.log(result);
        },
        function onerror(error) {
            console.log(error);
        },
        function onprogress(data) {
        });
}
相反,它似乎没有调用.then()中的任何函数,只是跳过了它!。已启用严格模式,因此我的令牌变量中确实包含承诺。否则它可能会出错,因为它无法找到.done()方法


我的问题是为什么会发生这种情况,以及如何获得我想要的预期行为(令牌中存储了来自getAccessTokenAsync的承诺,我可以通过其他方法访问该承诺)。

看起来您的then函数没有被调用,因为您没有调用承诺函数的完整回调。此外,您的WinJS.xhr是一个承诺,因此您可以返回该承诺,而无需将其包装在另一个承诺中。

在代码中,无需创建新的WinJS.promise,因为WinJS.xhr()将返回您想要的承诺。为了提供背景信息,有两种方法可以将完成的处理程序附加到承诺:.then和.done。两者都采用相同的参数,但返回值不同。done返回未定义的值,因为它用于承诺链的最末端

。然后,另一方面,返回已完成(或错误处理程序)返回时已实现的承诺,而实现值是已完成处理程序(或错误处理程序)返回的值

(顺便说一句,我已经写了很多关于澄清类似问题的承诺的文章。可以找到一个简短版本(Windows开发博客);更完整的版本可以在我的免费电子书的附录a“Demystifying Promissions”中找到,它现在正在第二次预览中。)

在编写您自己的异步函数时,调用其他现有异步函数(如WinJS.xhr)时使用的最佳模式是从其返回一个承诺。因此,在您的情况下,您希望getAccessTokenAsync如下所示:

getAccessTokenAsync = function (username, password) {
    var serializedData = {
        username: username, password: password,
    };

    return new WinJS.Promise(function (complete) {
        WinJS.xhr({
            type: "post",
            url: "http://127.0.0.1:8080/authenticate/login",
            responseType: "json",
            data: JSON.stringify(serializedData)
        }).done(
            function complete(result){
                return JSON.parse(result.responseText);
            }
        );
    })
}
getAccessTokenAsync = function (username, password) {
    var serializedData = {
        username: username, password: password,
    };

    return WinJS.xhr({
            type: "post",
            url: "http://127.0.0.1:8080/authenticate/login",
            responseType: "json",
            data: JSON.stringify(serializedData)
        }).then(
            function complete(result){
                return JSON.parse(result.responseText);
            }
        );
    })
}
return new WinJS.Promise(function (completeDispatch) {  //Name the dispatcher for clarity
    WinJS.xhr({
        type: "post",
        url: "http://127.0.0.1:8080/authenticate/login",
        responseType: "json",
        data: JSON.stringify(serializedData)
    }).done(
        function (result) {  //Keep this anonymous for clarity
            completeDispatch(JSON.parse(result.responseText));
        }
    );
})
这将返回一个承诺,您将其分配给令牌,其实现值将是来自JSON.parse(result.responseText)的结果

现在让我解释一下为什么您最初使用新的WinJS.Promise是不正确的——这是一个常见的误解,因为我的其他文章很清楚。您在这里给构造函数的函数参数本身接收三个参数。每个参数都是另一个函数,我称之为“dispatcher”,您可以得到一个完整、错误和进度。promise中的代码体会在适当的事件中调用这些调度器

然后,这些分派器依次为通过promise的.then或.done订阅的任何函数调用completed、error和progress处理程序。换句话说,调用这些分派器是您实际触发对这些处理程序的调用的唯一方法

现在,在您的原始代码中,您从来没有实际调用过其中任何一个。通过让WinJS.Promise构造函数只关注已完成的调度程序,您可以使它保持简单。但是,当您的WinJS.xhr调用完成时,您不会调用此调度器。造成混淆的部分原因是,您有一个名为complete的参数,然后将已完成的处理程序命名为WinJS.xhr()。如果在最后一个JSON.parse调用上设置了断点,它应该会被命中,但返回的值会被吞没,因为它从未传递给完整的调度程序

要更正此问题,您希望原始代码如下所示:

getAccessTokenAsync = function (username, password) {
    var serializedData = {
        username: username, password: password,
    };

    return new WinJS.Promise(function (complete) {
        WinJS.xhr({
            type: "post",
            url: "http://127.0.0.1:8080/authenticate/login",
            responseType: "json",
            data: JSON.stringify(serializedData)
        }).done(
            function complete(result){
                return JSON.parse(result.responseText);
            }
        );
    })
}
getAccessTokenAsync = function (username, password) {
    var serializedData = {
        username: username, password: password,
    };

    return WinJS.xhr({
            type: "post",
            url: "http://127.0.0.1:8080/authenticate/login",
            responseType: "json",
            data: JSON.stringify(serializedData)
        }).then(
            function complete(result){
                return JSON.parse(result.responseText);
            }
        );
    })
}
return new WinJS.Promise(function (completeDispatch) {  //Name the dispatcher for clarity
    WinJS.xhr({
        type: "post",
        url: "http://127.0.0.1:8080/authenticate/login",
        responseType: "json",
        data: JSON.stringify(serializedData)
    }).done(
        function (result) {  //Keep this anonymous for clarity
            completeDispatch(JSON.parse(result.responseText));
        }
    );
})
这也应该起作用。然而,正如我最初提到的那样,从WinJS.xhr().then()返回承诺仍然是最简单的,因为您根本不需要另一个承诺包装器

通过这些更改,您现在应该可以看到对getTokenExpiryAsync中已完成的处理程序的调用

现在让我们谈谈代码的其他部分。首先,即使存在错误条件,令牌也将始终设置为承诺,所以在getTokenExpiryAsync中永远不会看到null。其次,如果您像上面那样使用新的WinJS.Promise代码,您将永远不会看到错误或进度情况,因为您永远不会调用errorDispatcher或progressDispatcher。这是使用WinJS.xhr()返回的另一个很好的理由

因此,您需要更仔细地思考错误处理。确切地说,在什么情况下,您希望调用new Date()来表示到期?当xhr调用失败时,或者当成功调用的响应返回空时,您会这样做吗

处理错误的一种方法是使用上面新的WinJS.Promise变量和WinJS.xhr().done(),在这里您将错误处理程序订阅到.done。然后,在该错误处理程序中,通过调用completeDispather(new Date());,确定是要传播错误,还是仍要使用新日期履行包装承诺;。对于其他错误,您可以调用errorDispatcher。(请注意,所有这些都假设成功的xhr响应包含与new Date()相同的数据格式,否则您将混合数据值,并希望从响应中解析日期,而不是仅返回整个响应。)

我刚才描述的是一种很好的方法,可以捕获核心操作中的错误,然后注入一个默认值,我相信这是您想要的

另一方面,如果使用WinJS.xhr().then()中的返回值(第一个代码变量),则需要在getTokenExpiryAsync中放入更多此逻辑。(顺便说一句,正如您所展示的,这段代码是同步的,一条代码路径返回一个新的日期,另一条返回未定义的日期,因此它不会退出