[英]Wait for async method to finish
我正在尝试创建一个调用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()运算符,它允许您等到另一个observable发出以在出现错误时重试初始observable,例如:
return this.http.post(url, body...)
.retryWhen(errors => this.loginService.login(true))
.map(res => res.json());
试试retryWhen
试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直到满足某个条件时,我使用这个函数,我写的名为ploop(promise loop):
// 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返回一个promise,你应该能够将它与你的args一起传递给ploop。 您的done函数可以检查结果中的迭代或其他条件,以确定是否继续运行promise。
这是一个例子: http : //jsbin.com/xefutos/4/edit?js,console
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.