Каков наилучший способ передать разрешенные значения обещаний в финал, а затем в цепочку [дубликаты]

Я пытаюсь разобраться с обещаниями, используя модуль Q в node.js, однако у меня есть небольшая проблема.

В этом примере:

ModelA.create(/* params */)
.then(function(modelA){
    return ModelB.create(/* params */);
})
.then(function(modelB){
    return ModelC.create(/* params */);
})
.then(function(modelC){

    // need to do stuff with modelA, modelB and modelC

})
.fail(/*do failure stuff*/);

Метод .create возвращает промис, затем в каждом .then(), как и ожидалось, он получает разрешенное значение промиса.

Однако в финале .then() мне нужно иметь все 3 ранее разрешенных значения обещания.

Как лучше всего это сделать?


person MoSs    schedule 17.09.2013    source источник


Ответы (3)


Вот некоторые из ваших многочисленных вариантов:

За дверью 1 используйте сокращение для последовательного накопления результатов.

var models = [];
[
    function () {
        return ModelA.create(/*...*/);
    },
    function () {
        return ModelB.create(/*...*/);
    },
    function () {
        return ModelC.create(/*...*/);
    }
].reduce(function (ready, makeModel) {
    return ready.then(function () {
        return makeModel().then(function (model) {
            models.push(model);
        });
    });
}, Q())
.catch(function (error) {
    // handle errors
});

За дверью 2 упаковать накопившиеся модели в массив, и распаковать с разворотом.

Q.try(function () {
    return ModelA.create(/* params */)
})
.then(function(modelA){
    return [modelA, ModelB.create(/* params */)];
})
.spread(function(modelA, modelB){
    return [modelA, modelB, ModelC.create(/* params */)];
})
.spread(function(modelA, modelB, modelC){
    // need to do stuff with modelA, modelB and modelC
})
.catch(/*do failure stuff*/);

За дверью 3 зафиксируйте результаты в родительской области:

var models [];
ModelA.create(/* params */)
.then(function(modelA){
    models.push(modelA);
    return ModelB.create(/* params */);
})
.then(function(modelB){
    models.push(modelB);
    return ModelC.create(/* params */);
})
.then(function(modelC){
    models.push(modelC);

    // need to do stuff with models

})
.catch(function (error) {
    // handle error
});
person Kris Kowal    schedule 17.09.2013
comment
Прежде чем я разместил этот вопрос, я уже сделал это точно так же, как дверь № 3 :) Однако мне не слишком нравился этот подход, и я хотел узнать другие способы сделать это. Поэтому я выберу дверь №2, так как она не требует помощи внешней переменной. Кстати, я должен сказать, Крис, отличная работа с Q, пусть обратные вызовы умрут навсегда :) - person MoSs; 18.09.2013
comment
Мне нравится дверь №1 за ее продуманность, но на первый взгляд она совершенно нечитаема. Требуется некоторая сила ума, чтобы понять это, в то время как дверь номер 2 читается сразу. Спасибо за этот ответ :) - person Chev; 15.05.2015

Библиотека обещаний Bluebird предоставляет другое решение для этого через .bind().

Это выглядит так:

ModelA.create(/* params */).bind({})
.then(function (modelA) {
    this.modelA = modelA;
    return ModelB.create(/* params */);
})
.then(function (modelB) {
    this.modelB = modelB;
    return ModelC.create(/* params */);
})
.then(function (modelC) {
    // you have access to this.modelA, this.modelB and modelC;
});

Много интересной информации об этом методе есть в документации.

person justmoon    schedule 09.08.2014
comment
так что очень сильно выигрываю - person Abraham P; 13.11.2014

Вероятно, вам не нужно ждать, пока будет создана модель A, чтобы создать модель B и т. д.
Если это так, то вы можете сделать следующее:

var promises = [
  ModelA.create(...),
  ModelB.create(...),
  ModelC.create(...)
);

Q.all( promises ).spread(function( modelA, modelB, modelC ) {
  // Do things with them!
}).fail(function() {
  // Oh noes :(
});

Что это делает:

  • Создайте массив обещаний, по одному обещанию для каждой модели, которая вам нужна;
  • Выполнить все 3 промиса параллельно;
  • Выполнить функцию, переданную в spread(), когда все 3 промиса выполнены. Аргументы — это разрешенные значения для каждого промиса в порядке объявления.

Я надеюсь, что это поможет вам :)

person gustavohenke    schedule 17.09.2013
comment
Спасибо, это сработало в моей конкретной ситуации, однако все же я хотел бы знать, как выполнить эти обещания по порядку, и каждое из них ждет от предыдущего, чтобы выполниться и, в конце концов, получить результаты от всех. - person MoSs; 17.09.2013
comment
Один из способов сделать это — установить переменные в доступной области (например, той, которая была вызвана ModelA.create()). - person gustavohenke; 17.09.2013