javascript - Når regnes .then(success, fail) som et antipattern for promises?


Jeg tok en titt på bluebird promise FAQ, der det står at .then(success, fail) er et antipattern. Jeg forstår ikke helt forklaringen deres om try og catch. Hva er galt med følgende?

some_promise_call()
.then(function(res) { logger.log(res) }, function(err) { logger.log(err) })

Det ser ut til at eksemplet antyder at følgende er den riktige måten.

some_promise_call()
.then(function(res) { logger.log(res) })
.catch(function(err) { logger.log(err) })

Hva er forskjellen?

Svar #1

Hva er forskjellen?

Kallet .then() vil returnere et løfte som vil bli avvist dersom tilbakemeldingsfunksjonen kaster en feil. Dette betyr at når din suksess-logger feiler, vil feilen bli sendt til den følgende .catch()-tilbakemeldingsfunksjonen, men ikke til fail-tilbakemeldingsfunksjonen som følger med success.

Her er et kontrollflyt-diagram:

For å uttrykke det i synkron kode:

// some_promise_call().then(logger.log, logger.log)
then: {
    try {
        var results = some_call();
    } catch(e) {
        logger.log(e);
        break then;
    } // else
        logger.log(results);
}

Den andre log (som er som det første argumentet til .then()) vil bare bli utført i tilfelle ingen unntak skjedde. Den merkede blokken og break-setningen føles litt merkelig, dette er faktisk hva Python har try-except-else for (anbefalt lesning!).

// some_promise_call().then(logger.log).catch(logger.log)
try {
    var results = some_call();
    logger.log(results);
} catch(e) {
    logger.log(e);
}

catch-loggeren vil også håndtere unntak fra kall til suksessloggeren.

Så mye for forskjellen.

Jeg forstår ikke helt forklaringen om try og catch

Argumentet er at vanligvis vil du fange opp feil i hvert trinn av prosesseringen, og at du ikke bør bruke det i kjeder. Forventningen er at du kun har én sluttbehandler som håndterer alle feil - mens, når du bruker "antipattern", blir feil i noen av then-callbackene ikke håndtert.

Men dette mønsteret er faktisk veldig nyttig: Når du vil håndtere feil som oppsto akkurat i dette trinnet, og du vil gjøre noe helt annet når ingen feil oppstod - altså når feilen er uopprettelig. Vær oppmerksom på at dette grenser kontrollflyten din. Selvfølgelig er dette noen ganger ønsket.


Hva er galt med følgende?

some_promise_call()
.then(function(res) { logger.log(res) }, function(err) { logger.log(err) })

At du måtte gjenta tilbakeringen din. Du vil heller

some_promise_call()
   .catch(function(e) {
       return e; // it's OK, we'll just log it
   })
   .done(function(res) {
       logger.log(res);
   });

Du kan også vurdere å bruke .finally() for dette.

Svar #2

De to er ikke helt identiske. Forskjellen er at det første eksempelet ikke vil fange et unntak som blir kastet i din success-handler. Så hvis metoden din kun noen gang skal returnere oppfylte promises, som ofte er tilfelle, trenger du en avsluttende catch-handler (eller enda en then med en tom success-parameter). Selvfølgelig kan det være at then-handleren din ikke gjør noe som potensielt kan feile, i så fall kan det være greit å bruke en then med 2 parametere.

Men jeg tror poenget med teksten du lenket til er at then hovedsakelig er nyttig sammenlignet med callbacks i sin evne til å kjede en rekke asynkrone steg, og når du faktisk gjør dette, oppfører den 2-parameterversjonen av then seg subtilt ikke helt som forventet, av grunnen nevnt ovenfor. Det er spesielt kontraintuitivt når det brukes midt i kjeden.

Som en som har gjort mye komplekse asynkrone ting og støtt på hjørner som dette mer enn jeg liker å innrømme, anbefaler jeg virkelig å unngå dette anti-mønsteret og heller gå for tilnærmingen med separat handler.

Svar #3

Ved å se på fordeler og ulemper ved begge kan vi gjøre en kalkulert gjetning om hvilken som er passende for situasjonen. Dette er de to hovedtilnærmingene til å implementere løfter. Begge har sine fordeler og ulemper.

Fangstmetode

some_promise_call()
.then(function(res) { logger.log(res) })
.catch(function(err) { logger.log(err) })

Fordeler

  1. Alle feil håndteres av ett catch-blokk.
  2. Fanger til og med alle unntak i 'then'-blokken.
  3. Kjedet sammen flere suksesstilbakekallinger

Ulemper

  1. I tilfelle kjeding blir det vanskelig å vise forskjellige feilmeldinger.

Suksess/Feil-tilnærming

some_promise_call()
.then(function success(res) { logger.log(res) },
      function error(err) { logger.log(err) })

Fordeler

  1. Du får detaljert feilkontroll.
  2. Du kan ha en felles feilhåndteringsfunksjon for forskjellige typer feil, som databasefeil, 500-feil osv.

Ulemper

  1. Du vil fortsatt trenge en annen catch hvis du ønsker å håndtere feil som kastes av suksesscallbacken

Relaterte artikler