Anleitung zu JDeferred

Leitfaden für JDeferred

1. Überblick

JDeferred ist eine kleineJava-Bibliothek (unterstützt auchGroovy), die zum Implementieren einer asynchronen Topologie verwendet wird, ohne Boilerplate-Code zu schreiben. Dieses Framework ist von der FunktionJquery’s Promise/Ajaxund dem MusterAndroid’s Deferred Objectinspiriert.

In diesem Tutorial zeigen wir Ihnen, wie SieJDeferred und seine verschiedenen Dienstprogramme verwenden.

2. Maven-Abhängigkeit

Wir könnenJDeferred in jeder Anwendung verwenden, indem wir die folgenden Abhängigkeiten zu unserenpom.xml: hinzufügen


    org.jdeferred
    jdeferred-core
    1.2.6

Wir können die neueste Version desJDeferred-Projekts inCentral Maven Repository überprüfen.

3. Versprechen

Schauen wir uns einen einfachen Anwendungsfall an, bei dem ein fehleranfälliger synchroner Aufruf vonRESTAPIaufgerufen wird, und führen Sie eine Aufgabe basierend auf den von der API zurückgegebenen Daten aus.

In einer einfachen JQuery kann das obige Szenario folgendermaßen behandelt werden:

$.ajax("/GetEmployees")
    .done(
        function() {
            alert( "success" );
        }
     )
    .fail(
        function() {
            alert( "error" );
        }
     )
    .always(
        function() {
            alert( "complete" );
        }
    );

In ähnlicher Weise wirdJDeferred mit den SchnittstellenPromise undDeferred geliefert, die einen threadunabhängigen Hook für das entsprechende Objekt registrieren, der basierend auf diesem Objektstatus unterschiedliche anpassbare Aktionen auslöst.

Hier fungiertDeferred als Auslöser undPromise als Beobachter.

Wir können diese Art von asynchronem Workflow problemlos erstellen:

Deferred deferred
  = new DeferredObject<>();
Promise promise = deferred.promise();

promise.done(result -> System.out.println("Job done"))
  .fail(rejection -> System.out.println("Job fail"))
  .progress(progress -> System.out.println("Job is in progress"))
  .always((state, result, rejection) ->
    System.out.println("Job execution started"));

deferred.resolve("msg");
deferred.notify("notice");
deferred.reject("oops");

Hier hat jede Methode eine andere Semantik:

  • done() - wird nur ausgelöst, wenn die ausstehenden Aktionen für das zurückgestellte Objekt erfolgreich abgeschlossen wurden

  • fail() - wird ausgelöst, während eine Ausnahme ausgelöst wird, während ausstehende Aktionen für das zurückgestellte Objekt ausgeführt werden

  • progress() - wird ausgelöst, sobald anstehende Aktionen für das zurückgestellte Objekt gestartet werden

  • always() - wird unabhängig vom Status des zurückgestellten Objekts ausgelöst

Standardmäßig kann der Status eines zurückgestellten ObjektsPENDING/REJECTED/RESOLVED sein. Wir können den Status mit der Methodedeferred.state()überprüfen.

Hier ist zu beachten, dassonce a deferred object’s status is changed to RESOLVED, we can’t perform reject operation on that object.

Sobald der Status des Objekts inREJECTED, geändert wurde, können wir keine Operationresolve odernotify für dieses Objekt ausführen. Jeder Verstoß führt zu einemIllegalStateExeption.

4. Filter

Bevor wir das Endergebnis abrufen, können wir das verzögerte Objekt mitDoneFilter filtern.

Sobald die Filterung abgeschlossen ist, erhalten wir das thread-sichere verzögerte Objekt:

private static String modifiedMsg;

static String filter(String msg) {
    Deferred d = new DeferredObject<>();
    Promise p = d.promise();
    Promise filtered = p.then((result) > {
        modifiedMsg = "Hello "  result;
    });

    filtered.done(r > System.out.println("filtering done"));

    d.resolve(msg);
    return modifiedMsg;
}

5. Rohre

Ähnlich wie beim Filtern bietetJDeferred dieDonePipe-Schnittstelle, um anspruchsvolle Nachfilterungsaktionen auszuführen, sobald die ausstehenden Aktionen für zurückgestellte Objekte aufgelöst sind.

public enum Result {
    SUCCESS, FAILURE
};

private static Result status;

public static Result validate(int num) {
    Deferred d = new DeferredObject<>();
    Promise p = d.promise();

    p.then((DonePipe) result > {
        public Deferred pipeDone(Integer result) {
            if (result < 90) {
                return new DeferredObject()
                  .resolve(result);
            } else {
                return new DeferredObject()
                  .reject(new Exception("Unacceptable value"));
            }
    }).done(r > status = Result.SUCCESS )
      .fail(r > status = Result.FAILURE );

    d.resolve(num);
    return status;
}

Hier haben wir basierend auf dem Wert des tatsächlichen Ergebnisses eine Ausnahme ausgelöst, um das Ergebnis abzulehnen.

6. Aufgeschobener Manager

In einem Echtzeitszenario müssen wir uns mit den mehreren verzögerten Objekten befassen, die durch mehrere Versprechen beobachtet werden. In diesem Szenario ist es ziemlich schwierig, mehrere Versprechen separat zu verwalten.

Aus diesem Grund wirdJDeferred mit der SchnittstelleDeferredManagergeliefert, die einen gemeinsamen Beobachter für alle Versprechen schafft. Mit diesem gemeinsamen Beobachter können wir also gemeinsame Aktionen für alle Versprechen erstellen:

Deferred deferred = new DeferredObject<>();
DeferredManager dm = new DefaultDeferredManager();
Promise p1 = deferred.promise(),
  p2 = deferred.promise(),
  p3 = deferred.promise();
dm.when(p1, p2, p3)
  .done(result -> ... )
  .fail(result -> ... );
deferred.resolve("Hello example");

Wir könnenDeferredManager auchExecutorService mit einem benutzerdefinierten Thread-Pool zuweisen:

ExecutorService executor = Executors.newFixedThreadPool(10);
DeferredManager dm = new DefaultDeferredManager(executor);

Tatsächlich können wir die Verwendung vonPromise vollständig ignorieren und dieCallable-Schnittstelle direkt definieren, um die Aufgabe abzuschließen:

DeferredManager dm = new DefaultDeferredManager();
dm.when(() -> {
    // return something and raise an exception to interrupt the task
}).done(result -> ... )
  .fail(e -> ... );

7. Thread-sichere Aktion

Obwohl wir uns die meiste Zeit mit asynchronen Workflows befassen müssen, müssen wir manchmal auf die Ergebnisse aller parallelen Tasks warten.

In diesem Szenario dürfen wir nur diewait()-Methode vonObjectfürwait for all deferred tasks to finishverwenden:

DeferredManager dm = new DefaultDeferredManager();
Deferred deferred = new DeferredObject<>();
Promise p1 = deferred.promise();
Promise p = dm
  .when(p1)
  .done(result -> ... )
  .fail(result -> ... );

synchronized (p) {
    while (p.isPending()) {
        try {
            p.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

deferred.resolve("Hello example");

Alternativ können wir diewaitSafely()-Methode derPromise-Schnittstelle verwenden, um dasselbe zu erreichen.

try {
    p.waitSafely();
} catch (InterruptedException e) {
    e.printStackTrace();
}

Obwohl beide oben genannten Methoden fast dieselbe Leistung erbringen, ist es immer ratsam, die zweite zu verwenden, da für die zweite Prozedur keine Synchronisierung erforderlich ist.

8. Android-Integration

JDeferred können mithilfe des Android Maven-Plugins problemlos in Android-Anwendungen integriert werden.

Für den APKLIB-Build müssen wir die folgenden Abhängigkeiten inpom.xml hinzufügen:


    org.jdeferred
    jdeferred-android
    1.2.6
    apklib

FürAAR Build müssen wir die folgende Abhängigkeit inpom.xml hinzufügen:


    org.jdeferred
    jdeferred-android-aar
    1.2.6
    aar

9. Fazit

In diesem Tutorial haben wir uns mitJDeferred und den verschiedenen Dienstprogrammen befasst.

Wie immer ist der vollständige Quellcodeover on GitHub verfügbar.