then example await async jquery jquery-deferred

example - observable jquery



Retorno ya resuelto promesa (2)

@Eelk,

En mi experiencia, $.Deferred(function(def) {...}); la construcción raramente es necesaria, aunque supongo que puede ser bastante útil en algunas circunstancias.

En primer lugar, :

return $.Deferred(function(def) { def.resolve(); }).promise();

se simplificará a:

return $.Deferred().resolve().promise();

En segundo lugar, en DataService.makeRequest() puede evitar la necesidad de un $.Deferred explícito explotando .then() , de la siguiente manera:

function DataService() { var self = this; self.makeRequest = function (functionName, data) { return $.ajax({ type: "POST", url: "WebService.asmx/" + functionName, data: JSON.stringify(data), contentType: "application/json; charset=utf-8", dataType: "json" }).then(null, function (xhr, status, error) { var ex; try { ex = eval("(" + xhr.responseText + ")"); ex.message = ex.Message; ex.Message = undefined; } catch (ex2) { ex = { message: "Invalid Response From Server:/r/n" + xhr.responseText }; } if (ex.message == "LoginRequired") { app.viewModels.main.loginRequired(true); } else { app.showError(ex.message); } return ex.message; }); }; }

Los aspectos clave aquí son:

  • $.ajax() devuelve un objeto jqXHR compatible con la promesa, que (en caso de éxito / error) actúa inmediatamente y es modificado por .then() .
  • .then(null, ...) - hace que se transmita una nueva promesa, resuelta con los mismos valores que la promesa original devuelta por $.ajax() . Por lo tanto, bajo la condición de ''hecho'' (es decir, ajax success), .then() es completamente transparente.
  • return ex.message; - hace que se transmita una nueva promesa, rechazada con ex.message .

El efecto neto debería ser idéntico al código original, aunque, en mi humilde opinión, encadenar .then() es significativamente más limpio que configurar todo dentro de una devolución de llamada $.Deferred() .

Por cierto, puede evitar la necesidad de eval("(" + xhr.responseText + ")") etc. configurando un encabezado HTTP apropiado del lado del servidor de manera que su ''.Message'' aparezca directamente como el argumento de status (o xhr.status ?) de la devolución de llamada fallida. Por ejemplo, en PHP harías algo como:

$message = "my custom message"; header("HTTP/1.1 421 $message"); exit(0);

Estoy seguro de que ASP ofrece la misma capacidad.

IIRC, cualquier código de estado de la serie 4xx hará el trabajo. 421 simplemente resulta ser uno sin un significado específico.

Tengo un proyecto existente que tiene muchas funciones asincrónicas que devuelven promesas. Estoy agregando algo de almacenamiento en caché para que en algunos casos las funciones asíncronas se completen sincrónicamente y me gustaría hacer que este código sea más corto / mejor si es posible:

return $.Deferred(function(def) { def.resolve(); }).promise();

Por ejemplo, tengo una clase de servicio de datos que maneja la mayoría de las solicitudes AJAX que se ve así:

function DataService() { var self = this; self.makeRequest = function(functionName, data) { return $.Deferred(function(def) { var jsonData = JSON.stringify(data); $.ajax({ type: "POST", url: "WebService.asmx/" + functionName, data: jsonData, contentType: "application/json; charset=utf-8", dataType: "json", error: function(xhr, status, error) { var ex; try { ex = eval("(" + xhr.responseText + ")"); ex.message = ex.Message; ex.Message = undefined; } catch (ex2) { ex = { message: "Invalid Response From Server:/r/n" + xhr.responseText }; } if (ex.message == "LoginRequired") { app.viewModels.main.loginRequired(true); } else { app.showError(ex.message); } def.reject(ex.message); } }); }).promise(); } }

Luego tengo una función en otra clase que actualmente siempre llama a makeRequest:

self.deleteMe = function() { return app.dataservice.makeRequest(''deleteItem''); }

Quiero actualizar la función deleteMe para que no siempre llame a makeRequest, y en su lugar solo hace un trabajo sincrónico y luego regresa. Sin embargo, debe devolver una promesa, porque lo que sea que se llame lo esperará, pero debe ser una "promesa ya cumplida / resuelta". Actualmente estoy usando el primer conjunto de códigos de arriba para hacer eso. Parece que debe haber una mejor manera.


Simplemente use return $.when(); para devolver una promesa ya resuelta .

Si no le pasa ningún argumento, jQuery.when () devolverá una promesa resuelta.

Referencia: https://api.jquery.com/jquery.when/

Notas:

  • Esto es lo mismo que return $.when(undefined); lo que lleva al siguiente truco bastante genial que evita el uso de matrices y se apply .

Si desea esperar que se complete un número variable de promesas en paralelo , puede usar este patrón en un ciclo:

var promise; // Undefined is treated as an initial resolved promise by $.when while (insomeloop){ promise = $.when(promise, newpromise); }

luego haga una llamada final al finalizar con:

promise.then(function(){ // All done! });

p.ej

var promise;$.when var $elements = $(''.some-elements''); $elements.each(function(){ var $element = $(this).fadeout(); promise = $.when(promise, $element.promise()); }); promise.then(function(){ // All promises completed! });

Las desventajas son menores:

  • cada llamada a when envuelve la promesa anterior en una nueva promesa. Una sobrecarga menor y ya no es necesario mantener y evaluar una serie de promesas.
  • ningún valor puede pasarse directamente a la función final. Como normalmente no desea los valores de retorno de las promesas paralelas , esto es menor.
  • el fracaso de una sola promesa abortará la espera final anticipadamente, por lo que debe asegurarse de que se cumplan todas las promesas.