Явный сквозной
Подобно вложению обратных вызовов, этот метод основан на замыканиях. Тем не менее, цепочка остается плоской - вместо передачи только самого последнего результата, некоторый объект состояния передается для каждого шага. Эти объекты состояния накапливают результаты предыдущих действий, передавая все значения, которые понадобятся позже, плюс результат текущей задачи.
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
или Object.assign
в другой вспомогательной функции:
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
});
}
Хотя этот шаблон гарантирует плоскую цепочку, а явные объекты состояния могут улучшить четкость, он станет утомительным для длинной цепочки. Особенно, когда вам нужно государство только время от времени, вы все равно должны проходить его через каждый шаг. С этим фиксированным интерфейсом отдельные обратные вызовы в цепочке довольно тесно связаны и негибки для изменения. Это усложняет выделение отдельных шагов, и обратные вызовы не могут быть предоставлены напрямую из других модулей - они всегда должны быть заключены в стандартный код, который заботится о состоянии. Абстрактные вспомогательные функции, подобные приведенным выше, могут немного облегчить боль, но она всегда будет присутствовать.
javascript
, он актуален на другом языке. Я просто использую ответ «разорвать цепь» в java и jdeferred