Явне проходження
Подібно до вставки зворотних викликів, ця методика спирається на закриття. І все ж ланцюг залишається рівним - замість того, щоб передавати лише останній результат, для кожного кроку передається якийсь об'єкт стану. Ці об'єкти стану акумулюють результати попередніх дій, передаючи всі значення, які знадобляться згодом, плюс результат поточного завдання.
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
, воно є актуальним іншою мовою. Я просто використовую відповідь " Розбий