son sincronas que promesas programacion manejar las funciones ejecucion controlar asincronia asincronas asincrona java gwt

sincronas - promesas javascript



Indicador automático de ''carga'' al llamar a una función asíncrona (6)

Estoy buscando una manera de automatizar mostrar y ocultar un mensaje de ''carga'' cuando se llama a un servicio asíncrono, así que en lugar de hacer esto:

showLoadingWidget(); service.getShapes(dbName, new AsyncCallback() { public void onSuccess(Shape[] result) { hideLoadingWidget(); // more here... } public void onFailure(Throwable caught) { hideLoadingWidget(); //more here } });

Me gustaría hacer solo esto, pero aún así mostrar y ocultar el mensaje al finalizar.

// this should be gone: showLoadingWidget(); service.getShapes(dbName, new AsyncCallback() { public void onSuccess(Shape[] result) { // this should be gone: hideLoadingWidget(); // more here... } public void onFailure(Throwable caught) { //this should be gone: hideLoadingWidget(); //more here } });

En resumen, me gustaría cambiar el comportamiento de las llamadas asíncronas. Gracias por todas las sugerencias posibles.

Daniel


Aquí está mi versión, casi igual que las anteriores pero con algunas diferencias.

public abstract class LoadingAsyncCallback<T> implements AsyncCallback<T> { /** * Override this method and call the async service method providing the arguments needed. * @param args */ public abstract void callService(Object... args); /** * Call execute() to actually run the code in overriden method callService() * @param args: arguments needed for callService() method */ public void execute(Object... args) { //your code here to show the loading widget callService(args); } @Override public void onFailure(Throwable caught) { //your code here to hide the loading widget onCallbackFailure(caught); } @Override public void onSuccess(T result) { //your code here to hide the loading widget onCallbackSuccess(result); } public abstract void onCallbackFailure(Throwable caught); public abstract void onCallbackSuccess(T result); }

Un ejemplo simple podría ser el siguiente:

MyServiceAsync myServiceAsync = GWT.create(MyService.class); LoadingAsyncCallback loadingAsyncCallback = new LoadingAsyncCallback() { @Override public void callService(Object... args) { myServiceAsync.someMethod((String) args[0], (String) args[1], this); } @Override public void onCallbackFailure(Throwable caught) { } @Override public void onCallbackSuccess(Object result) { } }; String name = "foo"; String login = "bar"; loadingAsyncCallback.execute(name, login );


Ejemplo completo (Robert)

public abstract class AsyncCall<T> implements AsyncCallback<T> { public AsyncCall() { loadingMessage.show(); } public final void onFailure(Throwable caught) { loadingMessage.hide(); onCustomFailure(caught); } public final void onSuccess(T result) { hideLoadingMessage(); onCustomSuccess(result); } /** the failure method needed to be overwritte */ protected abstract void onCustomFailure(Throwable caught); /** overwritte to do something with result */ protected abstract void onCustomSuccess(T result); }


En caso de que alguien esté buscando una forma de marcar un elemento de pantalla (widget / componente) como ocupado durante una llamada RPC, he implementado una pequeña utilidad .

Deshabilita el componente e inserta un ''div'' con un estilo particular . Naturalmente, todo esto también puede ser deshecho.

Al momento de escribir este fue el estilo aplicado al div:

@sprite .busySpinner { gwt-image: "spinnerGif"; background-repeat: no-repeat; background-position: center; position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 10000; /* Something really high */ }

Y los métodos de utilidad:

/** * Disables the given component and places spinner gif over top. */ public static void markBusy(final Component c) { c.disable(); ensureNotBusy(c); // NOTE: Don''t add style to the component as we don''t want ''spinner'' to be disabled. c.getElement().insertFirst("<div class=''" + STYLE.busySpinner() + "''/>"); } /** * Enables the given component and removes the spinner (if any). */ public static void clearBusy(Component c) { c.enable(); if (!ensureNotBusy(c)) { GWT.log("No busy spinner to remove"); } } private static boolean ensureNotBusy(Component c) { Element first = c.getElement().getFirstChildElement(); if (first != null && first.removeClassName(STYLE.busySpinner())) { first.removeFromParent(); return true; } return false; }


Lo que estoy usando actualmente es la siguiente AsyncCall (inspirada en la solución de David Tinker). En lugar de volver a intentarlo, esto espera que algunas llamadas RPC demoren mucho tiempo en regresar y muestra un indicador de carga si la llamada no ha regresado antes de un tiempo de espera especificado.

Esta AsyncCall también realiza un seguimiento del número de llamadas RPC actualmente en curso, y solo oculta el indicador de carga si todas las llamadas RPC han regresado. Con la solución de David, el indicador de carga podría estar oculto por una llamada RPC anterior que regresa, aunque haya otro en curso. Esto si el curso asume que el widget indicador de carga es global para la aplicación, que es en mi caso.

public abstract class AsyncCall<T> { private static final int LOADING_TOLERANCE_MS = 100; private static int loadingIndicatorCount = 0; private Timer timer; private boolean incremented; private boolean displayFailure; public AsyncCall(boolean displayFailure) { this.displayFailure = displayFailure; timer = new Timer() { @Override public void run() { if (loadingIndicator++ == 0) // show global loading widget here incremented = true; } }; timer.schedule(LOADING_TOLERANCE_MS); call(new AsyncCallback<T>() { @Override public void onSuccess(T result) { timer.cancel(); if (incremented && --loadingIndicatorCount == 0) // hide global loading widget here callback(result); } @Override public void onFailure(Throwable caught) { timer.cancel(); if (incremented && --loadingIndicatorCount == 0) // hide global loading widget here if (AsyncCall.this.displayFailure) // show error to user here } }); protected abstract void call(AsyncCallback<T> cb); protected void callback(T result) { // might just be a void result or a result we // wish to ignore, so do not force implementation // by declaring as abstract } }


Podría crear una superclase de devolución de llamada predeterminada que tome un argumento de objeto LoadingMessage en su constructor y proporcione métodos de onSuccess0 para subclases, por ejemplo, onSuccess0 y onFailure0 .

La implementación sería similar a:

public final void onFailure(Throwable caught) { loadingMessage.hide(); onFailure0(caught); } protected abstract void onFailure0(Throwable caught);


Podría envolver la llamada en un objeto que maneja la visualización del mensaje de carga, tal vez volviendo a intentarlo algunas veces por errores o lo que sea. Algo como esto:

public abstract class AsyncCall<T> implements AsyncCallback<T> { /** Call the service method using cb as the callback. */ protected abstract void callService(AsyncCallback<T> cb); public void go(int retryCount) { showLoadingMessage(); execute(retryCount); } private void execute(final int retriesLeft) { callService(new AsyncCallback<T>() { public void onFailure(Throwable t) { GWT.log(t.toString(), t); if (retriesLeft <= 0) { hideLoadingMessage(); AsyncCall.this.onFailure(t); } else { execute(retriesLeft - 1); } } public void onSuccess(T result) { hideLoadingMessage(); AsyncCall.this.onSuccess(result); } }); } public void onFailure(Throwable t) { // standard error handling } ... }

Para hacer la llamada hacer algo como esto:

new AsyncCall<DTO>() { protected void callService(AsyncCallback<DTO> cb) { DemoService.App.get().someService("bla", cb); } public void onSuccess(DTO result) { // do something with result } }.go(3); // 3 retries

Podría extender esto con el código para detectar llamadas que están tomando mucho tiempo y mostrar un indicador de ocupado de algún tipo, etc.