等待异步方法完成
我正在尝试创建一个调用http请求的方法。如果请求返回401错误,我想重新登录并再次尝试请求。我的方法如下所示:等待异步方法完成
return this.http.post(url, this.cleanData(body), this.appendHttpHeaders(options))
.map(response => response)
.catch(error => {
if (error.status === 401) {
this.loginService.login(true).then(() => {
console.log("login should be finished: " + this.loginService.isLoggedIn());
return this.http.post(url, this.cleanData(body), this.appendHttpHeaders(options))
.map(response => response);
})
} else {
this.errorReportingService.reportHttpError(error);
return Observable.throw(error);
}
});
public login(forceLogin = false, loginCallback:() => any = null): Promise<String> {
...
console.log(1);
return new Promise((resolve, reject) => {
console.log(2);
this.popupLogin(loginCallback).then((result) => {
console.log(11);
resolve();
})
}).then(() => {
return new Promise((resolve, reject) => {
console.log(12);
resolve();
})
})
}
private popupLogin(loginCallback:() => any = null): Promise<String> {
...
console.log(3);
return new Promise((resolve, reject) => {
console.log(4);
this.handleLoginPopupFeedback(loginPopupHandle, loginCallback).then((result)=> {
console.log(9);
resolve();
})
}).then(() => {
return new Promise((resolve, reject) => {
console.log(10);
resolve("ok");
})
})
}
private handleLoginPopupFeedback(loginPopupHandle: Window, loginCallback:() => any = null): Promise<string> {
...
} else {
// ...popup is accessible, check values
let loginSuccessElement = loginPopupContent.getElementById('trucareOAuthLoginSuccess');
let loginFailureElement = loginPopupContent.getElementById('trucareOAuthLoginFailure');
if (!loginPopupHandle.closed &&
(loginSuccessElement === null || loginSuccessElement === undefined) &&
(loginFailureElement === null || loginFailureElement === undefined)
) {
console.log(5);
return new Promise((resolve, reject) => {
console.log(6);
setTimeout(() => {
console.log(7);
this.handleLoginPopupFeedback(loginPopupHandle, loginCallback).then((result) => {
console.log(8);
resolve();
}, 500)
})
});
}
...
}
return Promise.resolve("4");
}
问题是登录调用是异步的。有没有办法等待loginService.login()完成,然后再次尝试请求?
编辑:根据注释修改代码,但调用仍然不会重复,即使是console.log正在记录。但是,我甚至没有看到网络插口调用浏览器
你可以使用retryWhen()运营商,它可以让你等待,直到另一个观察的发射重试初始观察到的在错误的情况下,例如:
return this.http.post(url, body...)
.retryWhen(errors => this.loginService.login(true))
.map(res => res.json());
刚刚尝试retryWhen
:
.retryWhen(errors => {
return this.loginService.login(true).zip(errors).flatMap(([isLoggedIn, error]) => {
if(!isLoggedIn || error.status !== 401) {
return Observable.throw(error);
}
return Observable.of(true);
})
})
登录方法应该返回到什么程度?我有点困惑。现在它正在返回Promise,它没有数据,我只用于同步 – user3048782
一个observable,如果用户登录时发射true。发布您的登录服务,以便我们可以更好地为您提供帮助。 – cyrix
使用调用的方法编辑帖子。有更多的逻辑,但这并不重要。我不知道JavaScript,所以我猜这个承诺并不理想...... – user3048782
当我需要等到一定条件满足我使用这个功能我编写的名为ploop(承诺循环)运行,并重新运行一个承诺:
// fn : function that should return a promise.
// args : the arguments that should be passed to fn.
// donefn : function that should check the result of the promise
// and return true to indicate whether ploop should stop or not.
// promise: A promise value that is used internally by ploop and should never
// be passed in by the caller of ploop.
var ploop = function(fn, args, donefn, promise) {
return (promise || Promise.resolve(true))
.then(function() {
return(fn.apply(null, args));
})
.then(function(result) {
var finished = donefn(result);
if(finished === true){
return result;
} else {
return ploop(fn, args, donefn, promise);
}
});
};
这里是使用它的例子:
// Function that returns a promise
var searchForNumber = function(number) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
var min = 1;
var max = 10;
var val = Math.floor(Math.random()*(max-min+1)+min);
console.log('Value is: ' + val.toString());
return resolve(val);
}, 1000);
});
};
var searchFor = 4;
var donefn = function(result) {
return result == searchFor;
};
console.log('Searching for: ' + searchFor);
ploop(searchForNumber, [searchFor], donefn)
.then(function(val) {
console.log('Finally found! ' + val.toString());
process.exit(0);
})
.catch(function(err) {
process.exit(1);
});
由于您的http.get返回你应该能够在通过它与你的参数传递给ploop沿着一个承诺。您完成的功能可以检查结果中的迭代或其他条件,以确定是否继续运行诺言。
我不确定这是否会对我有帮助?我能够同步登录(您的版本更好)。我得到:“console.log(”登录应完成:“+ this.loginService.isLoggedIn());”。但下一行的呼叫永远不会完成。 – user3048782
您应该在this.loginService.login之前放置一个返回(true) –
不this.oginService.login()返回可观察到的? – cyrix
它没有。它所做的只是登录我 – user3048782
您需要让它返回一个承诺并使用该承诺。 – SLaks