Come gestire il se-altro nella promessa allora?


87

In alcuni casi, quando ottengo un valore di ritorno da un oggetto promessa, devo avviare due diverse then()precessioni a seconda delle condizioni del valore, come:

promise().then(function(value){
    if(//true) {
        // do something
    } else {
        // do something 
    }
})

Penso che forse posso scriverlo come:

promise().then(function(value){
    if(//true) {
        // call a new function which will return a new promise object
        ifTruePromise().then();
    } else {
        ifFalsePromise().then();
    }
})

ma con questo, ho due domande:

  1. Non sono sicuro che sia una buona idea iniziare una nuova promessa, poi elaborarla in una promessa;

  2. cosa succede se ho bisogno che i due processi chiamino una funzione nell'ultimo? Significa che hanno lo stesso "terminale"

Ho provato a restituire la nuova promessa per mantenere la catena originale come:

promise().then(function(value){
    if(//true) {
        // call a new function which will return a new promise object
        // and return it
        return ifTruePromise();
    } else {
        // do something, no new promise
        // hope to stop the then chain
    }
}).then(// I can handle the result of ifTruePromise here now);

ma in questo caso, che sia vero o falso, il prossimo thenfunzionerà.

Allora, qual è la migliore pratica per gestirlo?


1
potrebbe essere questo quello che stai cercando stackoverflow.com/questions/26599798/… ?
vinayr

Risposte:


61

Finché le tue funzioni restituiscono una promessa, puoi utilizzare il primo metodo che suggerisci.

Il violino sotto mostra come si possono prendere diversi percorsi di concatenamento a seconda di quale sarà il primo valore risolto.

function myPromiseFunction() {
	//Change the resolved value to take a different path
    return Promise.resolve(true);
}

function conditionalChaining(value) {
    if (value) {
        //do something
        return doSomething().then(doSomethingMore).then(doEvenSomethingMore);
    } else {
        //do something else
        return doSomeOtherThing().then(doSomethingMore).then(doEvenSomethingMore);
    }
}

function doSomething() {
    console.log("Inside doSomething function");
    return Promise.resolve("This message comes from doSomeThing function");
}

function doSomeOtherThing() {
    console.log("Inside doSomeOtherthing function");
    return Promise.resolve("This message comes from doSomeOtherThing function");
}

function doSomethingMore(message) {
    console.log(message);
    return Promise.resolve("Leaving doSomethingMore");
}

function doEvenSomethingMore(message) {
    console.log("Inside doEvenSomethingMore function");
    return Promise.resolve();
}

myPromiseFunction().then(conditionalChaining).then(function () {
    console.log("All done!");
}).
catch (function (e) {

});

Puoi anche fare un solo concatenamento condizionale, assegnare la promessa di ritorno a una variabile e quindi continuare a eseguire le funzioni che dovrebbero essere eseguite in entrambi i modi.

function conditionalChaining(value){
    if (value) {
        //do something
        return doSomething();
    } else{
        //do something else
        return doSomeOtherThing();
    }
}

var promise = myPromiseFunction().then(conditionalChaining);

promise.then(function(value){
    //keep executing functions that should be called either way
});

4

Ho scritto un semplice pacchetto per l'utilizzo della promessa condizionale.

Se vuoi verificarlo:

pagina npm: https://www.npmjs.com/package/promise-tree

e github: https://github.com/shizongli94/promise-tree

In risposta a commenti che chiedono come il pacchetto risolve il problema:

1, ha due oggetti.

2, l'oggetto Branch in questo pacchetto è un luogo di archiviazione temporaneo per le funzioni come onFulfilled e onRejected che si desidera utilizzare in then () o catch (). Ha metodi come then () e catch () che accettano gli stessi argomenti delle controparti in Promise. Quando si passa una richiamata in Branch.then () o Branch.catch (), utilizzare la stessa sintassi di Promise.then () e Promise.catch (). Quindi non fare altro che archiviare i callback in un array.

3, Condizione è un oggetto JSON che memorizza le condizioni e altre informazioni per il controllo e la ramificazione.

4, si specificano le condizioni (espressione booleana) utilizzando l'oggetto condizione nei callback di promessa. La condizione quindi memorizza le informazioni trasmesse. Dopo che tutte le informazioni necessarie sono state fornite dall'utente, l'oggetto condizione utilizza un metodo per costruire un oggetto Promise completamente nuovo che accetta le informazioni sulla catena di promesse e sul callback precedentemente memorizzate nell'oggetto Branch. Una piccola parte complicata qui è che tu (come implementatore, non utente) devi risolvere / rifiutare la promessa che hai costruito manualmente prima di concatenare i callback memorizzati. Questo perché altrimenti la nuova catena di promesse non inizierà.

5, Grazie al ciclo di eventi, gli oggetti Branch possono essere istanziati prima o dopo aver ottenuto un oggetto Promise radice e non interferiranno tra loro. Uso i termini "ramo" e "gambo" qui perché la struttura ricorda un albero.

Il codice di esempio può essere trovato su entrambe le pagine npm e github.

A proposito, questa implementazione consente anche di avere rami all'interno di un ramo. E le filiali non devono essere nello stesso posto in cui controlli le condizioni.


Sembra che tu stia fornendo commenti invece di rispondere. Una volta che avrai una reputazione sufficiente , sarai in grado di commentare qualsiasi post. Controlla anche questo cosa posso fare invece .
thewaywere

@thewaywewere, ho aggiunto i dettagli di implementazione in risposta alla tua richiesta.
szl1919

0

Questo è come l'ho fatto nel mio fetch () Non sono sicuro se questo sia il modo giusto, ma funziona

 fetch().then(res => res.ok ? res : false).then(res => {
    if (res) {
        //res ok
    } else {
       //res not ok
    }

});
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.