等待异步方法完成

时间:2017-02-23 17:32:13

标签: javascript angular typescript

我正在尝试创建一个调用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正在记录,调用仍然没有重复。但我甚至没有在浏览器的网络套接字中看到呼叫

1 个答案:

答案 0 :(得分:0)

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