繁体   English   中英

等待异步方法完成

[英]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());

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

当我需要运行并重新运行一个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.

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