Como evitar o jQuery promete completamente quando encadeia duas funções jQuery assíncronas?

Eu vi muitos tutoriais sobre as novas promises EMCA defendendo a prevenção das “promises” na biblioteca jQuery. Eles costumam dizer que você pode evitá-los, fazendo algo parecido com isto:

Promise.resolve($.getJSON(url, params)); // voila! the jQuery promise is "gone"! 

No entanto, isso realmente não funciona quando tenho que encadear duas funções jQuery assíncronas juntas. Como eu poderia encadear duas chamadas getJSON (onde a segunda chamada depende da primeira) juntas sem usar o jQuery’s then () ou .when ()?

Em vez disso, eu só quero usar Promise.all etc.

Eu acho que um problema de pergunta semelhante seria intercalar jquery e EMCA promete?

Você pode adotar uma das duas abordagens …

Converta e combine:

 var p1 = Promise.resolve($.getJSON(url_1, params_1)); // voila 1! var p2 = Promise.resolve($.getJSON(url_2, params_2)); // voila 2! var p3 = Promise.all([p1, p2]).then(...); 

Combine e depois converta:

 var p1 = $.getJSON(url_1, params_1); var p2 = $.getJSON(url_2, params_2); var p3 = Promise.resolve($.when(p1, p2)).then(...); // voila 1 and 2! 

Diretamente, qualquer abordagem lhe dará uma promise ES6 nativa, p3 , que resolve quando ambas as promises do jQuery resolverem, ou é rejeitada quando qualquer uma das promises falhar.

No entanto, provavelmente você está interessado nos resultados das duas chamadas getJSON() e o jQuery é estranho nesse aspecto. As promises do jqXHR do jQuery passam múltiplos parâmetros para seus retornos de sucesso e erro, enquanto que uma promise do ES6 aceitará apenas um; o resto será desconsiderado. Felizmente, é bastante simples agrupar os vários parâmetros para criar um único object. Isso deve ser feito no jQuery antes da conversão para o ES6.

O código “converter e combinar” se expande da seguinte maneira:

 var p1 = Promise.resolve($.getJSON(url_1, params_1).then( function(data, textStatus, jqXHR) { return { data:data, textStatus:textStatus, jqXHR:jqXHR }; }, function(jqXHR, textStatus, errorThrown) { return { jqXHR:jqXHR, textStatus:textStatus, errorThrown:errorThrown }; } )); var p2 = Promise.resolve($.getJSON(url_2, params_2).then( function(data, textStatus, jqXHR) { return { data:data, textStatus:textStatus, jqXHR:jqXHR }; }, function(jqXHR, textStatus, errorThrown) { return { errorThrown:errorThrown, textStatus:textStatus, jqXHR:jqXHR }; } )); var p3 = Promise.all([p1, p2]).then( function(results) { // results[0] will be an object with properties .data, .textStatus, .jqXHR // results[1] will be an object with properties .data, .textStatus, .jqXHR }, function(rejectVal) { // rejectVal will be an object with properties .errorThrown, .textStatus, .jqXHR } ); 

A abordagem “combinar e converter” é um pouco mais complicada à medida que os resultados combinados aparecem (em jQuery) como uma lista de arguments , que por sua vez precisa ser convertida (ainda em jQuery) em uma Matriz.

 var p1 = $.getJSON(url_1, params_1).then( function(data, textStatus, jqXHR) { return { data:data, textStatus:textStatus, jqXHR:jqXHR }; }, function(jqXHR, textStatus, errorThrown) { return { errorThrown:errorThrown, textStatus:textStatus, jqXHR:jqXHR }; } ); var p2 = $.getJSON(url_2, params_2).then( function(data, textStatus, jqXHR) { return { data:data, textStatus:textStatus, jqXHR:jqXHR }; }, function(jqXHR, textStatus, errorThrown) { return { errorThrown:errorThrown, textStatus:textStatus, jqXHR:jqXHR }; } ); var p3 = Promise.resolve($.when(p1, p2).then(function() { return [].slice.call(arguments);// < << convert arguments list to Array })).then( function(results) { // results[0] will be an object with properties .data, .textStatus, .jqXHR // results[1] will be an object with properties .data, .textStatus, .jqXHR }, function(rejectVal) { // rejectVal will be an object with properties .errorThrown, .textStatus, .jqXHR } ); 

DEMO: resolvido

DEMO: rejeitado

Promessas de JavaScript são interoperáveis . Você pode misturá-los como quiser, todas as bibliotecas apropriadas 1 e promises nativas aceitam 2 de qualquer implementação em qualquer lugar 3 . Se algo estrangeiro aparecer, eles apenas farão Promise.resolve .

Então normalmente você escreveria seu código como se todos eles usassem a mesma promise de implementação, e isso simplesmente funciona .
No entanto, agora você quer garantir que todas as chamadas de método estão usando sua implementação favorita. ou você deseja usar um método ou recurso não padrão? Para isso, você terá que lançar explicitamente todas as promises nas quais você está invocando methods – e nada mais.

Alguns exemplos:

 Promise.all([$.ajax(…), $.ajax(…)]).then(…); // just works! 
 $.ajax(…) // a jQuery promise .then(…) // so this would be jQuery `then`, which we don't want. 
 Promise.resolve($.ajax(…)) // explicit cast .then(function(data) { // native `then` return $.ajax(…); // just works! }) // returns a native promise still .catch(…) // so we can use its features 

1: Sim, jQuery não é um deles até a versão 3.0
2: todos os adiamentos e promises do jQuery são tão bons , embora
3: Realmente em todos os lugares que você esperaria uma promise, em Promise.resolve , em then , valores de retorno de retorno de chamada, Promise.all argumentos,…