简体   繁体   English

等待异步方法完成

[英]Wait for async method to finish

I am trying to create a method that calls a http request. 我正在尝试创建一个调用http请求的方法。 If the request returns 401 error, I would like to relogin and try the request again. 如果请求返回401错误,我想重新登录并再次尝试请求。 My method looks like this: 我的方法看起来像这样:

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");
}

Problem is that the login call is asynchronous. 问题是登录调用是异步的。 Is there a way to wait for loginService.login() to finish and then try request again? 有没有办法等待loginService.login()完成然后再次尝试请求?

EDIT: Modified the code according to the comments, but the call is still not repeated, even tho the console.log is logging. 编辑:根据注释修改代码,但调用仍然没有重复,即使console.log正在记录。 But I even don't see the call in networks sockets in browser 但我甚至没有在浏览器中看到网络套接字中的呼叫

You could use the retryWhen() operator, which lets you wait until another observable emits to retry an initial observable in case of error, eg: 您可以使用retryWhen()运算符,它允许您等到另一个observable发出以在出现错误时重试初始observable,例如:

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

Just try retryWhen : 试试retryWhenretryWhen

.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);
    })
  })

When I need to run and re-run a promise until a certain condition is met I use this function I wrote called ploop (promise loop): 当我需要运行并重新运行一个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);
        }
    });
};

And here is an example using it: 以下是使用它的示例:

// 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);
  });

Since your http.get returns a promise you should be able to pass it in to ploop along with your args. 由于你的http.get返回一个promise,你应该能够将它与你的args一起传递给ploop。 Your done function can check iterations or some other condition in the result to determine whether to keep running the promise or not. 您的done函数可以检查结果中的迭代或其他条件,以确定是否继续运行promise。

Here is an example: http://jsbin.com/xefutos/4/edit?js,console 这是一个例子: http//jsbin.com/xefutos/4/edit?js,console

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM