Resolva promessas angulares de funções “normais”

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 $httpserviç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 thenvocê 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 $resourcee, portanto, seu tutorial geralmente entrega os dados a outro componente do sistema para lidar com os dados thendo 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 undefinederro 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