Com base no título da pergunta "Resolver promessas uma após a outra (ou seja, em sequência)?", Podemos entender que o OP está mais interessado no tratamento sequencial de promessas na liquidação do que em chamadas sequenciais per se .
Esta resposta é oferecida:
- para demonstrar que chamadas seqüenciais não são necessárias para o processamento seqüencial de respostas.
- expor padrões alternativos viáveis aos visitantes desta página - incluindo o OP, se ele ainda estiver interessado mais de um ano depois.
- apesar da afirmação do OP de que ele não deseja fazer chamadas simultaneamente, o que pode realmente ser o caso, mas igualmente pode ser uma suposição com base no desejo de manipulação seqüencial de respostas, como o título indica.
Se chamadas simultâneas não são realmente desejadas, consulte a resposta de Benjamin Gruenbaum, que abrange chamadas sequenciais (etc) de forma abrangente.
Se, no entanto, você estiver interessado (para melhorar o desempenho) em padrões que permitam chamadas simultâneas seguidas de manipulação sequencial de respostas, continue lendo.
É tentador pensar que você deve usar Promise.all(arr.map(fn)).then(fn)
(como já fiz muitas vezes) ou o açúcar sofisticado de uma lib da Promise (principalmente o Bluebird), no entanto (com crédito para este artigo ) um arr.map(fn).reduce(fn)
padrão fará o trabalho, com as vantagens de:
- funciona com qualquer promessa de lib - mesmo versões pré-compatíveis do jQuery -
.then()
é usado apenas .
- oferece a flexibilidade de ignorar o erro ou parar no erro, o que você quiser com um mod de uma linha.
Aqui está, escrito para Q
.
var readFiles = function(files) {
return files.map(readFile) //Make calls in parallel.
.reduce(function(sequence, filePromise) {
return sequence.then(function() {
return filePromise;
}).then(function(file) {
//Do stuff with file ... in the correct sequence!
}, function(error) {
console.log(error); //optional
return sequence;//skip-over-error. To stop-on-error, `return error` (jQuery), or `throw error` (Promises/A+).
});
}, Q()).then(function() {
// all done.
});
};
Nota: apenas esse fragmento,, Q()
é específico para Q. Para o jQuery, você precisa garantir que readFile () retorne uma promessa do jQuery. Com A + libs, promessas estrangeiras serão assimiladas.
A chave aqui é a sequence
promessa da redução , que sequencia o tratamento das readFile
promessas, mas não a sua criação.
E depois que você absorve isso, talvez seja um pouco surpreendente quando você percebe que o .map()
palco não é realmente necessário! Todo o trabalho, chamadas paralelas e manipulação em série na ordem correta, pode ser realizado reduce()
sozinho, além da vantagem adicional de maior flexibilidade para:
- converter de chamadas assíncronas paralelas para chamadas assíncronas em série movendo apenas uma linha - potencialmente útil durante o desenvolvimento.
Aqui está, Q
novamente.
var readFiles = function(files) {
return files.reduce(function(sequence, f) {
var filePromise = readFile(f);//Make calls in parallel. To call sequentially, move this line down one.
return sequence.then(function() {
return filePromise;
}).then(function(file) {
//Do stuff with file ... in the correct sequence!
}, function(error) {
console.log(error); //optional
return sequence;//Skip over any errors. To stop-on-error, `return error` (jQuery), or `throw error` (Promises/A+).
});
}, Q()).then(function() {
// all done.
});
};
Esse é o padrão básico. Se você também quisesse entregar dados (por exemplo, os arquivos ou algumas transformações deles) ao chamador, seria necessária uma variante moderada.