У меня есть приложение для асинхронного javascript для браузера, и я хочу использовать обещания. Каждый асинхронный вызов имеет тот же шаблон, который может быть преобразован в обещание. Моя проблема в том, что у меня есть зависимости данных в цепочке обратного вызова. Некоторые упрощенный код:Преобразование цепи обратного вызова с зависимостями данных с обещаниями
getAlpha(function(err, alpha){
if(err) {handleError(err); return;}
getBeta(function(err, beta){
if(err) {handleError(err); return;}
getOmega(function(err, omega){
if(err) {handleError(err); return;}
getEpsilon(beta, function(err, epsilon){ // depends on beta
if(err) {handleError(err); return;}
getDelta(beta, function(err, delta){ // depends on beta
if(err) {handleError(err); return;}
console.log(alpha + beta + omega + epsilon + delta);
});
});
});
});
});
Я вижу две проблемы с обещаниями здесь:
Есть зависимостей данных между обратных вызовов. getEpsilon и getDelta зависят от бета-значения.
Мне нужны все собранные данные в последнем обратном вызове с самого первого вызова и другого.
Я смотрю здесь http://stuk.github.io/promise-me/ для некоторых примеров. Пример «Захваченные переменные» решает обе проблемы, но он делает ту же самую лестницу обратного вызова, которую мы видим без обещаний.
Другой способ - сделать объект данных для хранения всех обещаний. Это выглядит так:
var res = {};
getAlpha().then(function(alpha){
res.alpha = alpha;
return getBeta();
}).then(function(beta){
res.beta = beta;
return getOmega();
}).then(function(omega){
res.omega = omega;
return getEpsilon(res.beta);
}).then(function(epsilon){
res.epsilon = epsilon;
return getDelta(res.beta);
}).then(function(delta){
res.delta = delta;
console.log([res.alpha, res.beta, res.omega, res.epsilon, res.delta].join(' '));
}).catch(function(err){
handleError(err);
});
Интересно, можно ли решить эту проблему без вложенных вызовов и контейнера данных.
UPD 1. Мне очень жаль, но мое первое обещание не работает вообще, поэтому я делаю правильную версию.
UPD 2. В исходном коде каждый вызов get-LETTER является HTTP-запросом GET, поэтому эти вызовы могут работать параллельно.
UPD 3. Благодаря robertklep и Jeff Bowman. Я попробовал оба ответа. Мне нравится версия robertklep, потому что она очень короткая. После версии Jeff Bowman я понимаю много потенциальных проблем в моем асинхронном исполнении.
UPD 4. Я смешал свое первоначальное обещание с версией robertklep, чтобы добавить сахар.
var R = require('ramda');
// getAlpha returns alpha, etc.
var promiseObj = function(obj, res){
var promises = R.transpose(R.toPairs(obj));
return new Promise(function(resolve, reject){
Promise.all(promises[1]).then(function(results){
res = res || {};
resolve(R.merge(res, R.zipObj(promises[0], results)));
});
});
};
promiseObj({
'alpha' : getAlpha(),
'beta' : getBeta()
}).then(function(res){ // res: { alpha: 'alpha', beta: 'beta' }
return promiseObj({
'epsilon' : getEpsilon(res.beta),
}, res);
}).then(function(res){
console.log(res); // res: { alpha: 'alpha', beta: 'beta', epsilon: 'beta_epsilon' }
});
P.S.How do I access previous promise results in a .then() chain? дает ответ на мой вопрос тоже, но более общим образом.
Вы можете передать объект по цепочке, а затем уничтожить объект в каждой функции обещания.Если вы хотите, чтобы они были независимыми, вы можете передать массив, затем уничтожить его, выполнить функцию, вставить новое значение в массив и передать его в следующее обещание. – Yerken
Если вам просто нужно передать значение предыдущего обещания другому, объект, который вы использовали, не нужен, вы можете вернуть новое обещание в предыдущем обратном вызове и связать следующее обещание. getAlpha.then (getBeta) .then (getDelta); –
К сожалению, я хотел закрыть как дубликат [Как получить доступ к предыдущим результатам в цепочке .then()?] (Http://stackoverflow.com/q/28250680/1048572) – Bergi