Цепочка Angular $http звонит правильно?
Я читал около $q и promises в течение нескольких дней, и я, кажется, это понимаю... несколько. На практике я имею следующую ситуацию:
- Выполняется запрос $http и проверяется, может ли быть выполнен следующий вызов.
-
Если первый вызов завершился неудачно, верните "нет данных" , если он преуспеет и говорит, что вызов может быть выполнен, второй вызов выполняется, если нет - "нет данных" снова. Если второй вызов завершается успешно, он возвращает данные, если нет - "нет данных" . Похоже на это (примерно, я упрощен для общей идеи, поэтому не беспокойтесь о незначительных ошибках здесь):
return $http.get (something)
.then(function(allowedAccess){
if(allowedAccess){
return $http.get (somethingElse)
.then( function(result){return {data:result} },
function(error){return {data:"n0pe"} }
)
} else {
return {data:"n0pe"}
}
},
function(){ return {data:"n0pe"} });
Мне сказали использовать здесь $q. Я действительно не понимаю, как и почему. $Http-вызовы уже promises.
Если есть способ сделать это чище, я его не вижу. Просто перечитал этот пост по теме. По сути, я что-то упустил/есть лучший способ сделать это?
Изменить: также просто перечитать учебник по цепочке promises - он вообще не обрабатывает сбои вызовов. В основном публиковать это как должную осмотрительность.
Изменить 2: Это более подробно из теории, о которой я спрашиваю, выдержки из первой статьи:
Это простой пример. Это становится действительно мощным, если ваш обратный вызов then() возвращает другое обещание. В этом случае следующий then() будет выполняться только после того, как обещает решение. Этот шаблон может использоваться для последовательных HTTP-запросов, например (где запрос зависит от результата предыдущего):
Это, похоже, говорит о таких цепочках:
asyncFn1(1)
.then(function(data){return asyncFn2(data)})
.then(function(data){return asyncFn3(data)})
Итак, если я правильно понимаю это а). Не относится ко мне, потому что у меня нет третьей функции. б). Будет применяться ко мне, если бы у меня было три функции, потому что, когда я запускаю оператор if в первом запросе $http, и только внутри оператора if я возвращаю другое обещание. Итак, теоретически, если бы у меня было три функции асинхронного программирования, мне нужно было бы включить выражение if if в обещание?
Ответы
Ответ 1
Promises действительно помогает с составлением кода для создания асинхронных вызовов. Другими словами, они позволяют составить ваш код аналогичным образом, как вы создадите синхронный набор вызовов (с использованием цепочки .then
s), и как если бы код синхронизации был в try
/catch
block (с .catch
).
Итак, представьте, что ваши HTTP-вызовы блокировались - логика у вас будет выглядеть так:
var allowedAccess, data;
try {
allowedAccess = $http.get(something);
if (allowedAccess){
try{
var result = $http.get(somethingElse);
data = {data: result};
} catch (){
data = {data: "n0pe"};
}
} else {
data = {data: "n0pe"};
}
} catch (){
data = {data: "n0pe"};
}
return data;
Вы можете немного упростить его:
var allowedAccess, result;
try {
allowedAccess = $http.get(something);
var result;
if (allowedAccess) {
result = $http.get(somethingElse);
} else {
throw;
}
data = {data: result};
} catch () {
data = {data: "n0pe"};
}
return data;
И это переведёт в асинхронную версию:
return $http
.get(something)
.then(function(allowedAccess){
if (allowedAccess){
return $http.get(somethingElse);
} else {
return $q.reject(); // this is the "throw;" from above
}
})
.then(function(result){
return {data: result};
})
.catch(function(){
return {data: "n0pe"};
})
По крайней мере, это аргументы, которые вы могли бы применить при составлении кода с помощью ветвей и асинхронных вызовов.
Я не говорю, что представленная версия оптимальна или короче - она , однако более DRY из-за одной обработки ошибок. Но просто поймите, что когда вы делаете .then(success, error)
, это эквивалентно try
/catch
по предыдущей операции async - это может потребоваться или не понадобиться в зависимости от ваших конкретных обстоятельств.
Ответ 2
Вот как я бы назвал такую проблему:
// returns a promise that resolves some endpoint if allowed
function getDataWithAccess(allowed){
return allowed ? $http.get(someEndpoint) : $q.reject();
}
// do something with data
function handleData(data){
// do stuff with your data
}
// main chain
$http.get(accessCredEndpoint)
.then(getDataWithAccess)
.then(handleData)
.catch(function(err){
return { data: "n0pe" };
});
Да, это очень похоже на ответ "Новый разработчик", однако я хотел сделать вывод об извлечении функций в свои собственные блоки. Это делает код более понятным.
Ответ 3
$q поможет уменьшить пирамиду вызовов следующим образом:
async-call1.then(...
aysnc-call2.then(...
Это сообщение в блоге - http://chariotsolutions.com/blog/post/angularjs-corner-using-promises-q-handle-asynchronous-calls/ - предлагает чистый способ создания нескольких HTTP-запросов. Обратите внимание на более чистый подход с использованием $q. В случае, если вы ударили по одной конечной точке HTTP, использование вашего метода было бы просто прекрасным. Я бы сказал, что у вас все хорошо; $q может обеспечить большую гибкость в будущем.
Сообщение в блоге описывает службу при использовании $q, а код выглядит более чистым.
service('asyncService', function($http, $q) {
return {
loadDataFromUrls: function(urls) {
var deferred = $q.defer();
var urlCalls = [];
angular.forEach(urls, function(url) {
urlCalls.push($http.get(url.url));
});
// they may, in fact, all be done, but this
// executes the callbacks in then, once they are
// completely finished.
$q.all(urlCalls)
.then(...
Я тоже начинаю с promises, поэтому возьмите это с солью.