Явный сквозной
Подобно вложению обратных вызовов, этот метод основан на закрытии. Тем не менее, цепочка остается плоской - вместо передачи только последнего результата для каждого шага передается некоторый объект состояния. Эти объекты состояния накапливают результаты предыдущих действий, снова передавая все значения, которые потребуются позже, плюс результат текущей задачи.
function getExample() {
return promiseA(…).then(function(resultA) {
// some processing
return promiseB(…).then(b => [resultA, b]); // function(b) { return [resultA, b] }
}).then(function([resultA, resultB]) {
// more processing
return // something using both resultA and resultB
});
}
Здесь эта маленькая стрелка b => [resultA, b]
- это функция, которая закрывает resultA
и передает массив обоих результатов следующему шагу. В котором используется синтаксис деструктуризации параметров, чтобы снова разбить его на отдельные переменные.
До того, как деструктуризация стала доступной в ES6, изящный вспомогательный метод .spread()
был предоставлен многими библиотеками обещаний (Q, Bluebird, когда,…). Для использования в качестве .spread(function(resultA, resultB) { …
требуется функция с несколькими параметрами - по одному для каждого элемента массива.
Конечно, необходимое здесь закрытие можно дополнительно упростить с помощью некоторых вспомогательных функций, например
function addTo(x) {
// imagine complex `arguments` fiddling or anything that helps usability
// but you get the idea with this simple one:
return res => [x, res];
}
…
return promiseB(…).then(addTo(resultA));
В качестве альтернативы вы можете использовать Promise.all
для создания обещания для массива:
function getExample() {
return promiseA(…).then(function(resultA) {
// some processing
return Promise.all([resultA, promiseB(…)]); // resultA will implicitly be wrapped
// as if passed to Promise.resolve()
}).then(function([resultA, resultB]) {
// more processing
return // something using both resultA and resultB
});
}
И вы можете использовать не только массивы, но и объекты произвольной сложности. Например, с _.extend
или _ 10_ в другой вспомогательной функции:
function augment(obj, name) {
return function (res) { var r = Object.assign({}, obj); r[name] = res; return r; };
}
function getExample() {
return promiseA(…).then(function(resultA) {
// some processing
return promiseB(…).then(augment({resultA}, "resultB"));
}).then(function(obj) {
// more processing
return // something using both obj.resultA and obj.resultB
});
}
Хотя этот шаблон гарантирует плоскую цепочку, а явные объекты состояния могут улучшить ясность, для длинной цепочки он станет утомительным. Особенно, когда вам нужно состояние только время от времени, вам все равно придется проходить его через каждый шаг. С этим фиксированным интерфейсом отдельные обратные вызовы в цепочке довольно тесно связаны и негибки для изменения. Это затрудняет выделение отдельных шагов, а обратные вызовы не могут быть предоставлены напрямую из других модулей - они всегда должны быть заключены в шаблонный код, который заботится о состоянии. Абстрактные вспомогательные функции, подобные приведенным выше, могут немного облегчить боль, но они всегда будут присутствовать.
person
Bergi
schedule
31.01.2015
javascript
, он актуален для других языков. Я просто использую разрыв цепочки ответов в java и jdeferred - person gontard   schedule 09.12.2015