2015-06-09 4 views
5

Я работаю с обещаниями, и я застрял с моим прецедентом. У меня есть массив функций трансформатора (каждая функция является обещанием и изменяет некоторую структуру JSON).цепочка цепочек обещаний с bluebird

Позвольте мне показать код.

Позволяет сказать, что это моя структура JSON (массив)

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

transformFunction является определение функций преобразования изменения данных определенным образом. Эти две функции добавляет c и d свойство вышеуказанной структуры JSON:

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); 
     }) 
    }, 
    ... 
} 

От пользователя UI определяет, какой трансформатор функции он должен использовать и в каком порядке. Допустим, он выбрал нормальный порядок, как это:

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

Метод transform1 должен модифицировать данные и результат должен быть передан transform2 методу.

Я смотрел на: Promise.all, но, похоже, он не заботится о порядке обещаний, и, самое главное, он должен передать предыдущий результат следующему обещанию.

+2

Мне просто нужно спросить, но зачем вам использовать обещания для этого, это не асинхронно? – adeneo

+0

Я упростил его для вопроса, в реальном usecase я могу сделать запрос db или ajax-вызов там. – sensor

+0

Я не уверен, но из-за того, как вы его описываете, похоже, что вы просто хотите передать данные или что-то еще. Может быть, кто-то, у кого больше опыта работы с Bluebird, ответит, я только немного использовал его для пролонгации промежуточного программного обеспечения и т. Д. – adeneo

ответ

5

Примечание: Как отметил adeneo в комментариях, используйте обещания, только если вы имеете дело с асинхронным кодом.

  1. Создать массив функций, которые должны быть выполнены. И убедитесь, что все они возвращают Обещание.

  2. Затем вы можете использовать Promise.reduce, чтобы уменьшить начальное значение до преобразованного окончательного значения, возвращая результат выполнения текущей функции возврата обещания на каждой итерации.

  3. Наконец, вы можете приложить обработчик then, чтобы получить фактическое значение и обработчик catch, на всякий случай, если обещания отклоняются.

Допустим, у нас есть две функции преобразования, подобные этому.

Примечание: Я говорю снова. Вы никогда не должны использовать Promises с такими функциями. Вы должны использовать обещания только тогда, когда функции, с которыми вы имеете дело, действительно асинхронны.

// 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; 
    })); 
} 

Затем вы можете преобразовать исходное значение, как этот

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); 
    }); 

Выход

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

Вы можете цепи обещаниях образом вы всегда делать: с помощью .then().

Допустим, у вас есть эти два преобразования:

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

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

В реальном сценарии, они будут делать асинхронную работу. Вы могли бы просто:

increment(1).then(double) 

Но, вы не знаете порядок или количество преобразований. Давайте поместим их в массив, и then() их один за другим:

var transformations = [increment, double] 

var promise = Promise.resolve(1); 

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

Вы можете прикрепить catch() обработчик перед тем, как начать, после того, как вы закончите или даже за трансформацией.

Это неэффективно, если вы собираетесь применять сотни преобразований. В этом случае вы должны использовать reduce() как thefourtheye предлагает в своем ответе.

Смежные вопросы