2015-06-09 14 views
5

Sto lavorando a mio modo con le promesse e sono bloccato con il mio caso d'uso. Ho una matrice di funzioni di trasformatore (ogni funzione è una promessa e modifica una struttura JSON).catena di promesse con bluebird

Lasciami mostrare un po 'di codice.

Diciamo questo è mia struttura JSON (array)

var data = [{a: 1, b:2}, {a:3, b:4}]; 

transformFunction è definizione di trasformare funzioni modificano i dati in un certo modo. Le due funzioni aggiunge c e d struttura alla struttura JSON sopra:

var transformFunctions = { // 

    transform1: function (data) { // This function adds `c` property to each object from `a` 
     return new Promise(function (resolve) { 
      for (var i = 0; i < data.length; i++) { 
       data[i].c = data[i].a; 
      } 
      return resolve(data); 
     }) 
    }, 

    transform2: function (data) { // This function adds `d` property to each object from `c` 
     return new Promise(function (resolve) { 
      for (var i = 0; i < data.length; i++) { 
       data[i].d = data[i].c; 
      } 
      return resolve(data); 
     }) 
    }, 
    ... 
} 

L'utente da un utente specifica quali funzioni trasformatore dovrebbe usare e in quale ordine. Diciamo prese l'ordine normale in questo modo:

var userTransformList = ['transform1', 'transform2']; 

Il metodo transform1 deve modificare i dati e il risultato dovrebbe essere passato al transform2 metodo.

Stavo osservando: Promise.all ma sembra che non si preoccupi per l'ordine delle promesse, e soprattutto è necessario passare il risultato precedente alla prossima promessa.

+2

Devo solo chiedere, ma perché dovresti usare delle promesse per questo, non è asincrono? – adeneo

+0

L'ho semplificato per la domanda, nel caso reale posso fare una richiesta db o una chiamata ajax lì. – sensor

+0

Non ne sono sicuro, ma dal modo in cui lo descrivi, sembra che tu voglia solo filtrare i dati o qualcosa del genere. Forse qualcuno che ha più esperienza con Bluebird risponderà, l'ho usato solo un po 'per promettere il middleware ecc. – adeneo

risposta

5

Nota: Come indicato da adeneo nei commenti, utilizzare le promesse solo se si ha a che fare con codice asincrono.

  1. Creare una serie di funzioni che devono essere eseguite. E assicurati che tutti restituiscano una promessa.

  2. Quindi, è possibile utilizzare Promise.reduce per ridurre il valore iniziale al valore finale trasformato restituendo il risultato dell'esecuzione della funzione di ritorno della promessa corrente, ad ogni iterazione.

  3. Infine è possibile allegare un gestore then per ottenere il valore effettivo e un gestore catch, nel caso in cui le promesse vengano rifiutate.

Diciamo che abbiamo due funzioni di trasformazione come questa.

Nota: Sto raccontando di nuovo. Non dovresti mai usare Promises con funzioni come queste. Dovresti usare le promesse solo quando le funzioni con cui hai a che fare sono davvero asincrone.

// Just add a property called `c` to all the objects and return a Promise object 
function transform1(data) { 
    return Promise.resolve(data.map(function(currentObject) { 
     currentObject.c = currentObject.a + currentObject.b; 
     return currentObject; 
    })); 
} 

// Just add a property called `d` to all the objects and return a Promise object 
function transform2(data) { 
    return Promise.resolve(data.map(function(currentObject) { 
     currentObject.d = currentObject.a + currentObject.b + currentObject.c; 
     return currentObject; 
    })); 
} 

Quindi è possibile trasformare il valore originale, come questo

Promise.reduce([transform1, transform2], function (result, currentFunction) { 
     return currentFunction(result); 
    }, [{a: 1, b: 2}, {a: 3, b: 4}])  // Initial value 
    .then(function (transformedData) { 
     console.log(transformedData); 
    }) 
    .catch(function (err) { 
     console.error(err); 
    }); 

uscita

[ { a: 1, b: 2, c: 3, d: 6 }, { a: 3, b: 4, c: 7, d: 14 } ] 
4

È possibile concatenare promette il modo in cui fai sempre: usando .then().

Diciamo che avete questi due trasformazioni:

function increment(x) { 
    return Promise.resolve(x + 1); 
} 

function double(x) { 
    return Promise.resolve(2 * x); 
} 

In uno scenario reale, queste sarebbero facendo un lavoro asincrono. Si potrebbe semplicemente:

increment(1).then(double) 

Ma, voi non conoscete l'ordine o il numero di trasformazioni. Mettiamoli in un array, e then() uno per uno:

var transformations = [increment, double] 

var promise = Promise.resolve(1); 

for (var i = 0; i < transformations.length; i++) 
    promise = promise.then(transformations[i]); 

È possibile allegare un gestore catch() prima di iniziare, dopo aver completato o addirittura per-trasformazione.

Questo non è efficiente se si applicano centinaia di trasformazioni. In tal caso, è necessario utilizzare reduce() come thefourtheye suggerisce nella sua risposta.