Избегая вложенных обратных вызовов с помощью promises

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

function loadDependency1() {
    // return a promsise to load the first dependency
}

function loadDependency2(dependency1) {
    // return a promise to load the second dependency, which relies on the first dependency
}

function loadDependency3(dependency2) {
    // return a promise to load the third dependency, which relies on the second dependency
}

function doWork(dependency1, dependency2, dependency3) {
    // finally have all the things necessary to do work
}

// load all the dependencies and eventually doWork
loadDependency1().then(function(dependency1) {
    return loadDependency2(dependency1).then(function(dependency2) {
        return loadDependency3(dependency2).then(function(dependency3) {
            doWork(dependency1, dependency2, dependency3);
        });
    });
});

Ответ 1

Когда вы вернете обещание от then, оно решит, когда это обещание будет решено:

Итак, если следующий нужен только предыдущий:

loadDependency1().then(function(dependency1) {
    return loadDependency2(dependency1);
}).then(function(dependency2) {
     return loadDependency3(dependency2);
}).then(function(dependency3) {
    doWork(dependency3);
});

Работает, если вам нужна третья зависимость.

Если зависимости не зависят друг от друга:

Promise.all([loadDependency1(),loadDependency2(),loadDependency3])
.spread(function(dep1,dep2,dep3){
    doWork(dep1,dep2,dep3);
});

Если вы хотите сохранить "состояние" по цепочке обещаний и используете современную библиотеку обещаний, такую ​​как Bluebird, вы можете сделать:

loadDependency1().bind({}).then(function(dependency1) {
    this.dep1 = dependency1;
    return loadDependency2(dependency1);
}).then(function(dependency2) {
     this.dep2 = dependency2;
     return loadDependency3(dependency2);
}).then(function(dependency3) {
    doWork(this.dep1, this.dep2, dependency3);
});

Если вы не (и вы действительно должны быть:)), вы можете .all вы обойти его:

loadDependency1().then(function(dependency1) {
    return [loadDependency2(dependency1),dependency1];
}).spread(function(dependency2,dep1) {
     return [loadDependency3(dependency2),dependency2,dep1];
}).spread(function(dependency3,dependency2,dependency1) {
    doWork(dependency1, dependency2, dependency3);
});