2017-02-23 219 views
1

我正在尝试创建一个调用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正在记录。但是,我甚至没有看到网络插口调用浏览器

+0

不this.oginService.login()返回可观察到的? – cyrix

+0

它没有。它所做的只是登录我 – user3048782

+2

您需要让它返回一个承诺并使用该承诺。 – SLaks

回答

0

你可以使用retryWhen()运营商,它可以让你等待,直到另一个观察的发射重试初始观察到的在错误的情况下,例如:

return this.http.post(url, body...) 
    .retryWhen(errors => this.loginService.login(true)) 
    .map(res => res.json()); 
0

刚刚尝试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); 
    }) 
    }) 
+0

登录方法应该返回到什么程度?我有点困惑。现在它正在返回Promise,它没有数据,我只用于同步 – user3048782

+0

一个observable,如果用户登录时发射true。发布您的登录服务,以便我们可以更好地为您提供帮助。 – cyrix

+0

使用调用的方法编辑帖子。有更多的逻辑,但这并不重要。我不知道JavaScript,所以我猜这个承诺并不理想...... – user3048782

0

当我需要等到一定条件满足我使用这个功能我编写的名为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沿着一个承诺。您完成的功能可以检查结果中的迭代或其他条件,以确定是否继续运行诺言。

下面是一个例子:http://jsbin.com/xefutos/4/edit?js,console

+0

我不确定这是否会对我有帮助?我能够同步登录(您的版本更好)。我得到:“console.log(”登录应完成:“+ this.loginService.isLoggedIn());”。但下一行的呼叫永远不会完成。 – user3048782

+0

您应该在this.loginService.login之前放置一个返回(true) –