Produzir uma promise que depende de promises recursivas

Eu tenho uma matriz de ids inteiros, como

var a=[1,2,3,4,5] 

e eu tenho uma necessidade de realizar chamadas remotas assíncronas para cada um desses ids. Cada chamada é uma solicitação WebAPI realizada usando $ resource e apresentada como promise.

Eu preciso criar uma function que leva matriz desses IDs, em seguida, inicializa cadeia de promises recursivas. A cadeia deve resultar em chamadas webapi consequentes para cada um dos IDs, um por um. Essas chamadas não devem ser paralelas, mas encadeadas.

A function em questão retorna uma promise “principal” que deve ser resolvida ou rejeitada com base no resultado de chamadas da Web assíncronas. Ou seja, se alguma promise na recursion for rejeitada devido à desconexão do servidor, o principal prometido também deverá falhar. No caso normal, a promise “principal” deve ser resolvida no ponto em que todas as solicitações são concluídas.

Como posso conseguir isso em angularjs?

Você usa reduce longo da matriz para encadear as promises juntos. Não há necessidade de fazer isso recursivo.

 // for angularjs: var Q = $q.when; var p = a.reduce(function(prev, el) { return prev.then(function(arr) { return makeRequest(el).then(function(res) { return arr.concat([res]); }); }); }, Q([])); 

Este é realmente um pedido muito razoável.

A ferramenta que usamos para isso em bibliotecas sem um controle específico é:

 var a = [1,2,3,4,5]; var p = makeRequest(a.shift()); // use first element a.forEach(function(el){ p = p.then(function(result){ return makeRequest(el); }); }); p.then(function(){ // all requests done }); 

Observe que suponho que você tenha um método makeRequest aqui que faça uma única solicitação e retorne uma promise que seja cumprida quando essa solicitação for concluída.

Também é possível retornar os resultados das solicitações se você precisar disso usando uma matriz secundária:

 var a = [1,2,3,4,5]; var results = Array(a.length); var p = makeRequest(a.shift()). then(function(res){ results[0] = res;}); // use first element a.forEach(function(el,i){ p = p.then(function(result){ results[i] = result; return makeRequest(el); }); }); p = p.thenResolve(results); // resolve with results, in BB that'd be p.return(results) p.then(function(results){ // all requests done console.log(results); // array of response values }).catch(function(e){ // single failure }); 

Usando o ramo v2 da biblioteca Bluebird, você pode fazer:

  Promise.each([1,2,3,4,5],makeRequest).then(function(results){ // access results });