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中放入更多此逻辑。(顺便说一句,正如您所展示的,这段代码是同步的,一条代码路径返回一个新的日期,另一条返回未定义的日期,因此它不会退出