2017-10-05 3 views
0

Dire que j'ai un tableau d'objets qui ont des méthodes asynchrones:Créer cascade asynchrone à partir d'objets

[ 
    { 
    partOne: function(input) { 
     // Do something async 
    }, 
    partTwo: function(result) { 
     // Do something w/ result of partOne 
    } 
    }, 
    { 
    partOne: function(resultOfPrevious) { 
     // Do something async 
    }, 
    partTwo: function(result) { 
     // Do something w/ result of partOne 
    } 
    }, 
    { 
    partOne: function(resultOfPrevious) { 
     // Do something async 
    }, 
    partTwo: function(result) { 
     // Do something w/ result of partOne 
    } 
    } 
] 

Je veux exécuter PartOne du premier objet avec mon entrée, passer le résultat (async) à la fonction de rappel DEUXIEMEPARTIE , puis passez le résultat de partTwo en entrée à partOne de l'objet suivant et ainsi de suite. Le tableau peut être d'un ou plusieurs objets. Je me demande quel est le meilleur modèle pour exécuter ce genre de code?

Il est quelque peu similaire à la méthode de cascade de async.js: https://caolan.github.io/async/docs.html#waterfall, mais je me demande comment je peux le faire sans une bibliothèque et éventuellement avec un code plus propre?

Vous ne savez pas si async/await peut vous aider ici?

Répondre

2

une autre option sans recueillir chaque rappel à un tableau, en utilisant async/await:

async function processWaterfallObject (data, input) { 
    let result = input 

    for (let entry of data) { 
    result = await entry.partOne(result) 
    result = await entry.partTwo(result) 
    } 

    return result 
} 

Cela suppose que les fonctions de votre tableau data sont async ou renvoient un Promise.


async/await est actuellement soutenu par every major browser et est disponible en node depuis 7.6.0.

+0

Très bien, très propre. –

0

En supposant que votre tableau d'objets donnés dans la question initiale est sous une variable appelée cascade

let collector = []; 
for (waterfallObj of waterfall) { 
    let tempArr = Object.values(waterfallObj);//get the functions out of the object 
    for (waterfallFunc of tempArr) { 
    collector.push(waterfallFunc); 
    } 
} 
//now you have your functions in order in collector 
function recursiveCallback(i) { 
    if (i>collector.length-1) { 
    return;//if there are no more to call then return 
    } 

    collector[i]().then(function(){ 
    recursiveCallback(i+1); 
    }); 
} 

Si vous voulez que la fonction suivante à faire quelque chose avec la valeur des fonctions précédentes puis modifiez simplement puis ensuite (fonction (passedValue et utiliser alors que passedValue dans l'appel recursiveCallback en son sein

+0

Vous n'êtes pas 'pop'ping n'importe où à partir de' collector', donc la fonction 'recursiveCallback' va juste lancer avec' la taille maximale de la pile d'appels dépassée'. –

+0

Pourquoi aurais-je besoin de pop? J'ai une déclaration de retour là-bas pour quand toutes les fonctions de collectionneurs ont été traitées – Shard

+0

Mon mauvais, vous avez tout à fait raison. J'ai oublié la partie "je ...". –

1

Voici une fonction simple pour appeler chaque fonction asynchrone dans une pile

function drain(stack, initialArg) { 
    stack.reduce(function (sectArg, section) { 
    return Object.keys(section).reduce(async function (arg, key) { 
     return await section[key].call(null,arg) 
    }, sectArg) 
    }, initialArg) 
} 

Pour l'utiliser en sorte que chaque fonction vous empilez renvoie une valeur

var stack = [ 
    { 
    partOne: function(input) { 
     // Do something async 
     console.log('section one partOne', input) 
     return 'section one partOne output' 
    }, 
    partTwo: function(result) { 
     // Do something w/ result of partOne 
     console.log('section one partTwo', result) 
     return 'section one partTwo output' 
    } 
    }, 
    { 
    partOne: function(resultOfPrevious) { 
     // Do something async 
     console.log('section two partOne', resultOfPrevious) 
     return 'section two partOne output' 
    }, 
    partTwo: function(result) { 
     // Do something w/ result of partOne 
     console.log('section two partTwo', result) 
     return 'section two partTwo output' 
    } 
    }, 
    { 
    partOne: function(resultOfPrevious) { 
     // Do something async 
     console.log('section three partOne', resultOfPrevious) 
     return 'section three partOne output' 
    }, 
    partTwo: function(result) { 
     // Do something w/ result of partOne 
     console.log('section three partTwo', result) 
     return 'section three partTwo output' 
    } 
    } 
] 

Alors que vous pouvez invoquer la pile comme

drain(stack, 'initialArg') 

Voir cette jsFiddle: https://jsfiddle.net/kqj0rror/

+0

Cela ne tient pas compte des fonctions asynchrones. –

+0

J'ai édité pour accommoder les fonctions asynchrones – kharhys

+0

Super! J'ai également remarqué que vous appelez 'section' [key]' avec 'this' - je ne suis pas sûr que ce soit une bonne idée, cela pourrait conduire à beaucoup de bogues inattendus dans le code. Peut-être que vous devriez peut-être utiliser 'null' à la place? –