Хорошая вещь в обещаниях заключается в том, что они делают простую аналогию между синхронным кодом и асинхронным кодом. Для иллюстрации (с использованием библиотеки Q):
синхронный:
var thisReturnsAValue = function() {
var result = mySynchronousFunction();
if(result) {
return getOneValue();
} else {
return getAnotherValue();
}
};
try {
var value = thisReturnsAValue();
console.log(value);
} catch(err) {
console.error(err);
}
Asynchronous:
var Q = require('q');
var thisReturnsAPromiseForAValue = function() {
return Q.Promise(function() {
return myAsynchronousFunction().then(function(result) {
if(result) {
// Even getOneValue() would work here, because a non-promise
// value is automatically cast to a pre-resolved promise
return getOneValueAsynchronously();
} else {
return getAnotherValueAsynchronously();
}
});
});
};
thisReturnsAPromiseForAValue().then(function(value) {
console.log(value);
}, function(err) {
console.error(err);
});
Вам просто нужно привыкнуть к мысли, что вернуть значения всегда доступны в качестве аргументов тогда -callbacks, и это обещание цепочки равнозначно составлению вызовов функций (f(g(h(x)))
) или иным образом выполнение функций последовательно (var x2 = h(x); var x3 = g(x2);
). Это по существу это! Вещи немного сложны, когда вы вводите ветви, но вы можете понять, что делать с этих первых принципов. Поскольку then-callbacks принимают обещания как возвращаемые значения, вы можете изменить значение, полученное асинхронно, возвращая еще одно обещание для асинхронной операции, которая разрешает новое значение на основе старого, а родительское обещание не будет разрешаться до тех пор, пока новый один решает! И, конечно же, вы можете вернуть эти обещания изнутри ветвей if-else.
Другая действительно хорошая вещь, проиллюстрированная в примере выше, заключается в том, что обещания (по крайней мере, совместимые с обещаниями/A +) обрабатывают исключения аналогичным образом. Первая ошибка «поднята» обходит обратные вызовы и пузырьки без ошибок до первого доступного обратного вызова ошибки, как и блок try-catch.
Для чего это стоит, я думаю, пытаясь имитировать это поведение с помощью обработанных вручную обратных вызовов типа Node.js, а библиотека async
- это свой особый вид ада :).
После этих принципов код стал бы (предполагая, что все функции являются асинхронным и возвращать обещания):
beginTransaction().then(function() {
// beginTransaction() has run
return updateUsers(); // resolves the boolean value `updated`
}).then(function(updated) {
// updateUsers() has "returned" `updated`
if(updated) {
if(isBusiness) {
return updateBusiness().then(function(updated) {
if(!updated) {
return insertBusiness();
}
// It's okay if we don't return anything -- it will
// result in a promise which immediately resolves to
// `undefined`, which is a no-op, just like a missing
// else-branch
});
} else {
return deleteBusiness();
}
} else {
if(upsert) {
return insertUser().then(function() {
if(isBusiness) {
return insertBusiness();
}
});
}
}
}).then(function() {
return commitTransaction();
}).done(function() {
console.log('all done!');
}, function(err) {
console.error(err);
});
Я думаю, что это справедливый вопрос. Все эти операции предположительно асинхронны? – mooiamaduck
Да @mooiamaduck. На самом деле я делаю вставки/обновления баз данных, которые являются асинхронными. – Eduardo
Вы смотрите на 'koa.js' (или' co', если вы не пишете веб-приложение)? Если вы использовали koa и обещания, это выглядело бы очень точно так же, как вы его там.Или, если вы хотите использовать прямые обратные вызовы, вы можете использовать библиотеку управления потоком, такую как 'async' (например, посмотрите на функцию' async.auto'. – Kevin