2017-09-18 6 views
1

J'ai découvert les promesses javascript récemment. Un avantage annoncé est l'imbrication propre en enchaînant les clauses.achèvement d'une promesse, avant de commencer la suivante, dans une longue liste

Mon code fonctionne comme prévu, mais l'imbrication devient tout aussi moche que lorsque j'ai utilisé des rappels. Y a-t-il une meilleure façon d'utiliser le chaînage d'alors pour supprimer toute cette imbrication? Remarque J'ai besoin de terminer la tâche n avant que quoi que ce soit dans la tâche n + 1 puisse commencer.

Le simple exemple fixe

'use strict'; 

function P1() { 

    return new Promise((resolve) => { 
     console.log("starting 1") 

     setTimeout(() => { 
      console.log("done 1") 
      resolve(); 
     }, 100) 
    }) 
} 

function P2() { 

    return new Promise((resolve) => { 
     console.log("must start 2 only after 1 is done") 

     setTimeout(() => { 
      console.log("done 2") 
      resolve(); 
     }, 50) 
    }) 
} 

function P3() { 

    return new Promise((resolve) => { 
     console.log("must start 3 only after 3 is done") 

     setTimeout(() => { 
      console.log("done 3") 
      resolve(); 
     }, 10) 
    }) 
} 

console.log("this works, but if list was long, nesting would be terribly deep"); 
// start 1, done 1, start 2, done 2, start 3, done 3. 
P1().then(() => { 
    P2().then(() => { 
     P3() 
    }) 
}) 

D'après les commentaires que je l'aurais fait

P1().then(() => { 
    return P2() 
}).then(() => { 
    return P3() 
}).catch(() => { console.log("yikes something failed")}) 

Le code réel reçoit un tableau de choses à traiter de manière séquentielle. Le format suggéré ci-dessus ne convient que lorsque la séquence d'étapes est spécifiée en tant que code. On dirait qu'il devrait y avoir une sorte de Promise.do_these_sequentialy, plutôt que mon code construisant explicitement la chaîne de promesses. Comme suit:

'use strict'; 


function driver(single_command) { 
    console.log("executing " + single_command); 

    // various amounts of time to complete command 
    return new Promise((resolve) => { 
     setTimeout(() => { 
      console.log("completed " + single_command); 
      resolve() 
     }, Math.random()*1000) 
    }) 
} 

function execute_series_of_commands_sequentialy(commands) { 
    var P = driver(commands.shift()); 

    if (commands.length > 0) { 
     return P.then(() => { return execute_series_of_commands_sequentialy(commands) }) 
    } else { 
     return P 
    } 
} 

execute_series_of_commands_sequentialy([1, 2, 3, 4, 5, 6, 7, 8, 9]).then(() => { 
    console.log("test all done") 
}) 

Répondre

1

Vous avez mal compris le fonctionnement de Promises. Vous pouvez les valeurs de retour de la chaîne ainsi que les instances de promesse et de les transmettre plus loin le long de la chaîne:

P1() 
.then(() => P2()) 
.then(() => P3()) 

Il n'y a pas besoin de les imbriquer.

0

Jetez un oeil à async/await qui simplifie grandement l'écriture des promesses.

JavaScript’s Async/Await Blows Promises Away

Fondamentalement, il consiste à écrire des fonctions async comme le code de synchronisation:

async function P(number) { 
 
    return new Promise((resolve) => { 
 
     console.log("starting "+number) 
 

 
     setTimeout(() => { 
 
      console.log("done "+number) 
 
      resolve(); 
 
     }, 800) 
 
    }) 
 
} 
 

 
/* Or the ES6 version : 
 
    const P = async (number) => new Promise((resolve) => { ... }) 
 
*/ 
 

 
async function run(){ 
 
    await P(1) 
 
    await P(2) 
 
    await P(3) 
 
    
 
    console.log("All done!") 
 
} 
 

 
run()

1

Personnellement, j'aime la façon dont ce format ressemble et est ce que j'utilise

foo(){ 
    P1().then(()=>{ 
    return P2(); 
    }).then(()=>{ 
    return P3(); 
    }).catch((err)=>{ 
    //handle errors 
    }); 
}