O que a maioria dos tutoriais do Angular Promise falham em lhe ensinar: Criando a promessa
Muitas vezes, enquanto aprendia como usar promessas, ou tentava usá-las em meus aplicativos Angular, eu descobria peças de funcionalidade que precisavam ser uma promessa, mas não eram $resource
(ou um de seus derivados).
A maioria dos tutoriais mostra o resultado final de algo assim:
function(){
var deferred = $q.defer(); // creates a deferred object
var itFailed = deferred.reject();
$http.get('http://some/api')
.success() // a success function
.error(ifFailed('API failure. Try turning API server off then on.')) // promise rejected, but considered resolved by using defer.reject()
.then(function(data){
deferred.resolve(data);
})
return deferred.promise;
}
Isso é muito útil! Mas e se você precisar de uma promessa para algo diferente de uma chamada de API? Como o $http
serviço já é uma promessa, tudo o que você realmente aprendeu aqui foi como resolver uma promessa a partir de uma função que já era uma promessa. Então, o que você faz quando precisa resolver uma promessa do resultado de uma chamada de função que ainda não é uma promessa?.then()
As promessas estão vazias (inglês | javascript)
À primeira vista, essa afirmação pode parecer bastante evidente. Como tudo em javascript, uma promessa é um objeto. Mas, um objeto de promessa é … um pouco estranho. As promessas nascem quando um objeto diferido é criado, como uma propriedade do objeto diferido. A promessa é considerada resolvida quando essa propriedade tem um valor ou o objeto de funçãomethod
$q
adiada (a on ) inicia outra propriedade com a qual todos estamos familiarizados: uma rejeição.
As promessas são criadas adiando qualquer coisa (inglês | javascript)
Outra afirmação evidente, mas você vê onde isso vai dar. As promessas são a mesma coisa no javascript e na vida real, mas na vida real raramente consideramos o que torna uma promessa uma promessa. Programação I, onde os 0’s não se tornam 1’s apenas porque precisamos que o façam, temos de ser muito claros sobre o que torna uma promessa uma promessa.
Uma promessa é formada quando uma ação é adiada. Na vida real, esse é um conceito que não pensamos bem. Se você disser a seus filhos “nós estamos indo para a Disneylândia”, você sabe que acabou de fazer uma promessa (mesmo que tenha mentido). Mas o que você não percebe é que você não apenas criou uma promessa da ação de ir para a Disneylândia, você também criou a promessa de ter que tomar a decisão de ir para a Disneylândia … até o ponto em que você realmente entrar os portões .
No desenvolvimento Angular, percebemos o conceito facilmente quando precisamos reagir a uma promessa. Nós temos algumas grandes ferramentas para fazer isso: , , , e `prometo [ ‘finalmente’]. Mas para saber quando usá-los, precisamos conectar a lacuna entre o javascript e a realidade..then()
.success()
error()
Então eu posso usar (Inglês | javascript).when()
.then()
O erro que a maioria dos tutoriais deixa em você é a confusão sobre um objeto de promessa e um objeto adiado. Nenhum pode existir sem o outro, mas um objeto de promessa não é um objeto adiado . É um objeto filho. Muitas vezes, depois de passar por um tutorial de promessa Angular, eu assim os desenvolvedores fazem algo como:
var goToDisneyland = $q.deferred();
deferred.then(buyMickeyMouseEars);
Mas se você me acompanhou até este ponto, a peça que está faltando se tornou aparente. O então na vida real acontece quando um evento ocorre depois que a promessa é cumprida, mas depois que a promessa é feita. O que then
você normalmente quer em javascript só acontece depois que a promessa é resolvida . (essas consequências não são os andróides que você está procurando).
Isso é crítico. Já que os métodos javascript herdam prototipicamente de seus pais. Chamar um objeto adiado não lançará nenhum erro, porque é uma coisa completamente válida de se fazer. Mas significa que sua função se tornará uma condição de corrida, com um pequeno salto inicial..then()
then
Portanto, a menos que você queira comprar suas orelhas de Mickey Mouse depois de chegar à Disneylândia, e não da venda de garagem de seus vizinhos, é melhor anexar isso ao objeto da promessa, e não ao objeto adiado.
Então é aqui que a maioria dos tutoriais dá errado. Eles mostram isso:
var deferred = $q.defer();
Mas não este: <a id=”missingLine”> </a>
var promise = deferred.promise;
Geralmente, isso ocorre porque a maioria dos tutoriais enfoca o uso da resolução de valores adiados retornados de um $resource
e, portanto, seu tutorial geralmente entrega os dados a outro componente do sistema para lidar com os dados then
do mundo. Então, eles ficariam assim (usando na expressão de retorno):defer().promise
Seu objetivo: compre as orelhas do Mickey Mouse na Disneylândia
O tutorial ensina a você: Como chegar à Disneylândia
O que está faltando: ensinando você a esperar até chegar à Disneylândia para comprar suas orelhas do Mickey Mouse
Resultado final: você comprou orelhas do Mickey Mouse na liquidação de garagem do vizinho 3 meses antes da viagem
Por que é importante: Papai comprou confuso e realmente significava Coney Island, e eles odeiam ratos
.factory('myService', ['$http',function($http){
var goToDisneyland = $q.defer();
// api call on directions to disneyland
$http('http://directions to disneyland')
.then(function(data){ // <----- no promises here, just getting directions so I can fulfill that promise!
goToDisneyland.resolve(directions); // <---- assumes I'm going to buy my Mickey Mouse ears in another component
}
return goToDisneyland.promise // <--- where the heck did this come from!?
}]);
Se você, como muitos outros, deseja definir suas coisas dentro de seu serviço (digamos que você está sendo razoável e seu serviço é um modelo, e deseja enviar um e-mail apenas após uma compra bem-sucedida do cliente), pode acabar precisando de um expressão em seu modelo, apenas no caso de o conhecimento do papai sobre o parque temático estar um pouco enferrujado..then
.then
Comprar orelhas de Mickey Mouse não é uma promessa de ação, é uma ação
.factory('myService', ['$http',function($http){
var goToDisneyland = $q.defer(); // <---- implies I guess I think I just maybe made a promise?
// ok, let's get to buying those ears, because in my other component won't let me on any rides unless I have authentic ones
goToDisneyland().then(buyMickeyMouseEars); // <--- seems legit, and doesn't throw errors. Let's go on some rides!
promise.resolve();
return goToDisneyland.promise
}]);
Ei, filho, são falsificações
Analisei o cenário, retornei uma promessa e defini uma maneira de resolver a promessa. mas isso acaba com sua promessa executada antes que a condição certa fosse cumprida, e provavelmente você encontrou um undefined
erro ou retornou um conjunto de dados que está no estado errado. Uma linha de código deve esclarecer tudo isso. Dica: eu já mostrei essa linha aqui
Da próxima vez, saberemos melhor
Este é o seu serviço, agora baseado na vergonha:
.factory('myService', ['$http',function($http){
var makePromiseToGoToDisneyland = $.defer() // or simply in most apps: var deferred = $q.defer()
var goToDisneyland = deferred.promise; // this was the promise that was inerently created
// ok, let's get to buying those ears, because in my other component won't let me on any rides unless I have authentic ones
goToDisneyland().then(buyMickeyMouseEars); // <--- from the gift shop this time!! All day pass!!!
promise.resolve();
// hand master plan off to the wife for approval to make promise
return makePromiseToGoToDisneyland.goToDisneyland
}]);
As promessas estão vazias (javascript | inglês)
// coming soon, less words more code alternative
As promessas são criadas adiando qualquer coisa (inglês | javascript)
// coming soon, less words more code alternative
Então eu posso usar (Inglês | javascript).when()
.then()
// coming soon, less words more code alternative