2015-05-27 8 views
6

Korzystam z biblioteki obietnic Bluebird. Mam łańcuch promisified funkcji takich jak następuje:Jak można powtórzyć po wyjątku w JavaScript podczas korzystania z obietnic?

receiveMessageAsync(params) 
    .then(function(data)) { 
     return [data, handleMessageAsync(request)]; 
    }) 
    .spread(function(data, response) { 
     return [response, deleteMessageAsync(request)]; 
    }) 
    .spread(function(response, data) { 
     return sendResponseAsync(response); 
    }) 
    .then(function(data) { 
     return waitForMessage(data); 
    }) 
    .catch (function(err) { 
     // handle error here 
    }); 

Czasami sendMessage nie powiedzie się z powodu, powiedzmy, serwer do reagowania na nie jest dostępna. Chcę, aby kod nadal próbował odpowiadać na wieki, dopóki to się nie powiedzie. Nie można po prostu zawinąć sendMessage w catch, ponieważ tak naprawdę nie wyrzuca wyjątku, jak przypuszczam, wywołuje funkcję "error", która w tym promisified code jest "catch" na dole. Musi być więc jakiś sposób na "ponowienie" wysłania wiadomości w sekcji "catch". Problem polega na tym, że nawet jeśli spróbuję powtórzyć pętlę w "haczyku", nadal nie mam możliwości, aby przeskoczyć do łańcucha obietnic i wykonać pozostałe promnizowane funkcje. Jak sobie z tym poradzić?

EDIT:

Moja ponawiania przez HTTP POST zakończył się patrzy tak:

function retry(func) { 
    return func() 
     .spread(function(httpResponse) { 
      if (httpResponse.statusCode != 200) { 
       Log.error("HTTP post returned error status: "+httpResponse.statusCode); 
       Sleep.sleep(5); 
       return retry(func); 
      } 
     }) 
     .catch(function(err) { 
      Log.err("Unable to send response via HTTP"); 
      Sleep.sleep(5); 
      return retry(func); 
     }); 
} 
+0

Nie widzę tutaj "sendMessage". – Jacob

+0

Przepraszam, sendResponse powinno być sendMessage – Mike

+0

Myślę, że to interesujące, że powiedziałem, że chcę ponowić próbę na zawsze, ale każda odpowiedź do tej pory została napisana tylko dla skończonej liczby ponownych prób. Musi być coś takiego w pętli na zawsze, co przeszkadza ludziom. – Mike

Odpowiedz

7

Oto funkcja próbka ponawiania (jeszcze nie testowane):

function retry(maxRetries, fn) { 
    return fn().catch(function(err) { 
    if (maxRetries <= 0) { 
     throw err; 
    } 
    return retry(maxRetries - 1, fn); 
    }); 
} 

Chodzi o to, że możesz zawinąć funkcję, która zwraca obietnicę z czymś, co złapie i ponowi próbę po błędzie, aż skończy się liczba ponownych prób. Więc jeśli masz zamiar ponowić sendResponseAsync:

receiveMessageAsync(params) 
.then(function(data)) { 
    return [data, handleMessageAsync(request)]; 
}) 
.spread(function(data, response) { 
    return [response, deleteMessageAsync(request)]; 
}) 
.spread(function(response, data) { 
    return retry(3, function() { return sendResponseAsync(response); }); 
}) 
.then(function(data) { 
    return waitForMessage(data); 
}) 
.catch (function(err) { 
    // handle error here 
}); 

Skoro obietnica retry nie będzie faktycznie rzucać aż wszystkie prób zostały wyczerpane, twój łańcuch rozmowa może być kontynuowana.

Edit:

Oczywiście, zawsze można pętli na zawsze, jeśli preferowane:

function retryForever(fn) { 
    return fn().catch(function(err) { 
    return retryForever(fn); 
    }); 
} 
+0

'return retry (3, function() {return sendResponseAsync (response);});' może być 'return retry (3, sendResponseAsync.bind (null, response));' – mido

+2

Tak długo, jak długo nie jesteś używając starożytnego JS. – Jacob

+0

Proszę wyjaśnić, co robi .bind (null, response) i jak działa. Użyłem binda wcześniej, ale tylko w sensie .bind (this), aby uzyskać dostęp do zakresu mojego obiektu w łańcuchu obietnic. – Mike

2

Oto mały pomocnik, który działa jak then ale ponawia funkcję.

Promise.prototype.retry = function retry(onFulfilled, onRejected, n){ 
    n = n || 3; // default to 3 retries 
    return this.then(function(result) { 
     return Promise.try(function(){ 
      return onFulfilled(result); // guard against synchronous errors too 
     }).catch(function(err){ 
      if(n <= 0) throw err; 
      return this.retry(onFulfilled, onRejected, n - 1); 
     }.bind(this)); // keep `this` value 
    }.bind(this), onRejected); 
}; 

Który pozwolił napisać kod ładniejsza jak:

receiveMessageAsync(params) 
.then(function(data)) { 
    return [data, handleMessageAsync(request)]; 
}) 
.spread(function(data, response) { 
    return [response, deleteMessageAsync(request)]; 
}) 
.retry(function(response, data) { 
    return sendResponseAsync(response); // will retry this 3 times 
}) 
.then(function(data) { 
    return waitForMessage(data); 
}) 
.catch (function(err) { 
    // I don't like catch alls :/ Consider using `.error` instead. 
}); 
+1

proszę nie rozszerzać tubylców ... lub jeśli tak, sprawdź przynajmniej: 'if (! Promise.prototype.retry) {' –

0

Właśnie wydany https://github.com/zyklus/promise-repeat, który ponawia obietnicę, dopóki to albo czasy się lub maksymalna liczba prób jest trafiony. To pozwala na pisanie:

receiveMessageAsync(params) 
... 
.spread(retry(
    function(response, data) { 
     return sendResponseAsync(response); 
    } 
)) 
... 
0

Można użyć tej promise-retry komponent open source, które RETRIES funkcję zwracającą obietnicę.

Przykład:

promiseRetry((retry, number) => promiseFunction().catch(retry),{retries:3}) 
.then((result) => console.log(result)).catch(err => console.log(err)) 

Oto jak to działa:

const retry = require('retry'); 


const isRetryError = (err) => (err && err.code === 'RETRYPROMISE'); 

const promiseRetry = (fn, options) => { 

    const operation = retry.operation(options); 

    return new Promise((resolve, reject) => { 
     operation.attempt((number) => { 
       return fn(err => { 
        if (isRetryError(err)) { 
         err = err.retried; 
        } 
        throw {err:'Retrying', code:'RETRYPROMISE', message: err.message}; 
       }, number) 

      .then(resolve, (err) => { 
       if (isRetryError(err)) { 

        if (operation.retry(err || new Error())) { 
         return; 
        } 
       } 

       reject(err); 
      }); 
     }); 
    }); 
} 

Można również użyć this NPM package do pracy.

Powiązane problemy