JDeferred ist eine Java Deferred/Promise-Bibliothek, die dem Deferred Object von JQuery ähnelt.
Inspiriert von JQuery und Android Deferred Object.
Wenn Sie JDeferred 1.x verwenden, lesen Sie die JDeferred 1.x-Dokumentation
.then(…)
.filter(…)
.pipe(…)
.done(…)
.fail(…)
.progress(…)
.always(…)
.pipeAlways(…)
.when(p1, p2, p3, …).then(…)
.race(p1, p2, p3, …).then(…)
.settle(p1, p2, p3, …).then(…)
.when(new Runnable() {…})
.race(new Runnable() {…})
.settle(new Runnable() {…})
Deferred<Integer, Exception, Double> deferred;
deferred.resolve(10);
deferred.reject(new Exception());
deferred.notify(0.80);
< dependency >
< groupId >org.jdeferred.v2</ groupId >
< artifactId >jdeferred-core</ artifactId >
< version >${version}</ version >
</ dependency >
compile 'org.jdeferred.v2:jdeferred-core:${version}'
Verfügbare Versionen finden Sie im Maven Central Repository.
Kompatibilitätsberichte zwischen Versionen:
Deferred deferred = new DeferredObject ();
Promise promise = deferred . promise ();
promise . done ( new DoneCallback () {
public void onDone ( Object result ) {
...
}
}). fail ( new FailCallback () {
public void onFail ( Object rejection ) {
...
}
}). progress ( new ProgressCallback () {
public void onProgress ( Object progress ) {
...
}
}). always ( new AlwaysCallback () {
public void onAlways ( State state , Object result , Object rejection ) {
...
}
});
Mit dem Verweis auf das zurückgestellte Objekt können Sie dann Aktionen/Updates auslösen:
deferred . resolve ( "done" );
deferred . reject ( "oops" );
deferred . notify ( "100%" );
Verwenden Sie seit 2.0.0-Beta2
.filter(...)
anstelle von.then(...)
Deferred d = …;
Promise p = d . promise ();
Promise filtered = p . filter ( new DoneFilter < Integer , Integer >() {
public Integer filterDone ( Integer result )
return result * 10 ;
}
});
filtered . done ( new DoneCallback < Integer >() {
public void onDone ( Integer result ) {
// result would be original * 10
System . out . println ( result );
}
});
d . resolve ( 3 ) -> 30.
Verwenden Sie seit 2.0.0-Beta2
.pipe(...)
anstelle von.then(...)
Deferred d = ...;
Promise p = d . promise ();
p . pipe ( new DonePipe < Integer , Integer , Exception , Void >() {
public Deferred < Integer , Exception , Void > pipeDone ( Integer result ) {
if ( result < 100 ) {
return new DeferredObject < Integer , Void , Void >(). resolve ( result );
} else {
return new DeferredObject < Integer , Void , Void >(). reject ( new Exception (...));
}
}
}). done (...). fail (...);
d . resolve ( 80 ) -> done !
d . resolve ( 100 ) -> fail !
DeferredManager dm = new DefaultDeferredManager ();
Promise p1 , p2 , p3 ;
// initialize p1, p2, p3
dm . when ( p1 , p2 , p3 )
. done (…)
. fail (…)
Sie können auch einen Executor-Service für Ihren Bedarf angeben.
DeferredManager dm = new DefaultDeferredManager(myExecutorService);
Sie können Callable und Runnable fast wie ein Promise ohne zusätzlichen Aufwand verwenden.
DeferredManager dm = new DefaultDeferredManager ();
dm . when ( new Callable < Integer >(){
public Integer call () {
// return something
// or throw a new exception
}
}). done ( new DoneCallback < Integer >() {
public void onDone ( Integer result ) {
...
}
}). fail ( new FailCallback < Throwable >() {
public void onFail ( Throwable e ) {
...
}
});
Wenn Sie den Fortschritt innerhalb Ihres Callable oder Runnable benachrichtigen müssen, müssen Sie entweder Ihr eigenes Deferred-Objekt und Promise erstellen oder Sie können DeferredCallable und DeferredRunnable verwenden.
Verwenden Sie Ihr eigenes verzögertes Objekt
final Deferred deferred = ...
Promise promise = deferred . promise ();
promise . then (…);
Runnable r = new Runnable () {
public void run () {
while (…) {
deferred . notify ( myProgress );
}
deferred . resolve ( "done" );
}
}
Oder DeferredRunnable erweitern
DeferredManager dm = …;
dm . when ( new DeferredRunnable < Double >(){
public void run () {
while (…) {
notify ( myProgress );
}
}
}). then (…);
Seit 1.0.1
Normalerweise möchten Sie bei Verwendung dieses Frameworks Dinge asynchron erledigen. Wenn Sie jedoch warten müssen, bis alle zurückgestellten Aufgaben abgeschlossen sind, können Sie die Methoden Object.wait oder Promise.waitSafely verwenden.
Promise p = dm . when (...)
. done (...)
. fail (...)
synchronized ( p )
while ( p . isPending ()) {
try {
p . wait ();
} catch ( InterruptedException e ) { ... }
}
}
Alternativ können Sie eine einfachere Verknüpfung verwenden
Promise p = dm . when (...)
. done (...)
. fail (...)
try {
p . waitSafely ();
} catch ( InterruptedException e ) {
...
}
Das ist ziemlich cool, wenn es mit Java 8 Lambda verwendet wird!
dm . when (() -> {
return "Hey!" ;
}). done ( r -> System . out . println ( r ));
dm . when (
() -> { return "Hello" ; },
() -> { return "World" ; }
). done ( rs ->
rs . forEach ( r -> System . out . println ( r . getResult ()))
);
Aufrufe von when
mit mehreren Argumenten führen zu einem Promise
, dass Signale bei der ersten Ablehnung fail
oder Signale mit allen berechneten Werten done
.
Callable < Integer > c1 = () -> 1 ;
Callable < Integer > c2 = () -> 2 ;
Callable < Integer > c3 = () -> 3 ;
Promise < MultipleResults3 < Integer , Integer , Integer >, OneReject < Throwable >, MasterProgress > p = dm . when ( c1 , c2 , c3 );
p . done ( MultipleResults3 < Integer , Integer , Integer > r -> {
Assert . assertEquals ( r . getFirst (), 1 );
Assert . assertEquals ( r . getSecond (), 2 );
Assert . assertEquals ( r . getThird (), 3 );
});
Callable < Integer > c1 = () -> 1 ;
Callable < Integer > c2 = () -> 2 ;
Callable < Integer > c3 = () -> throw new RuntimeException ( "boom!" );
Promise < MultipleResults3 < Integer , Integer , Integer >, OneReject < Throwable >, MasterProgress > p = dm . when ( c1 , c2 , c3 );
p . done ( MultipleResults3 < Integer , Integer , Integer > r -> Assert . fail ( "should not be called" ))
. fail ( OneReject < Throwable > r -> Assert . assertEquals ( r . getReject (). getMessage (), "boom!" ));
Seit 2.0.0
Aufrufe von when
mit mehreren Argumenten (bis zu fünf) führen zu Ergebnissen mit typsicheren Gettern.
Seit 2.0.0
Aufrufe zum race
mit mehreren Argumenten führen zu einem Promise
, dass Signale bei der ersten Ablehnung fail
oder Signale bei der ersten Lösung done
.
Callable < Integer > c1 = () -> { Thread . sleep ( 200 ); return 1 ; };
Callable < Integer > c2 = () -> { Thread . sleep ( 100 ); return 2 ; };
Callable < Integer > c3 = () -> { Thread . sleep ( 200 ); return 3 ; };
Promise < OneResult <?>, OneReject < Throwable >, Void > p = dm . race ( c1 , c2 , c3 );
p . done ( OneResult <?> r -> Assert . assertEquals ( r . getResult (), 2 ));
Callable < Integer > c1 = () -> { Thread . sleep ( 200 ); return 1 ; };
Callable < Integer > c2 = () -> { Thread . sleep ( 100 ); throw new RuntimeException ( "boom!" ); };
Callable < Integer > c3 = () -> { Thread . sleep ( 200 ); return 3 ; };
Promise < OneResult <?>, OneReject < Throwable >, Void > p = dm . race ( c1 , c2 , c3 );
p . done ( OneResult <?> r -> Assert . fail ( "should not be called" )
. fail ( OneReject < Throwable > r -> Assert . assertEquals ( r . getReject (). getMessage (), "boom!" ));
Seit 2.0.0
Aufforderungen zur settle
mit mehreren Argumenten führen zu einem Promise
, das alle Lösungen und Ablehnungen sammelt.
Callable < Integer > c1 = () -> { Thread . sleep ( 200 ); return 1 ; };
Callable < Integer > c2 = () -> { Thread . sleep ( 100 ); throw new RuntimeException ( "boom!" ); };
Callable < Integer > c3 = () -> { Thread . sleep ( 200 ); return 3 ; };
Promise < AllValues , Throwable , MasterProgress >, Void > p = dm . race ( c1 , c2 , c3 );
p . done ( AllValues r -> {
Assert . assertEquals ( r . get ( 0 ). getValue (), 1 );
Assert . assertTrue ( r . get ( 1 ). getValue () instanceof RuntimeException );
Assert . assertEquals ( r . get ( 2 ). getValue (), 3 );
});
Seit 2.0.0
Manchmal wird eine Aufgabe während der Ausführung abgebrochen und erfordert die Bereinigung aller zugewiesenen Ressourcen. Sie können beispielsweise eine Aufgabe definieren, die die Schnittstelle org.jdeferred2.CancellationHandler
implementiert, oder mit einer solchen Implementierung ein zusätzliches Argument an DeferredFutureTask
übergeben
final DataSource datasource = ...;
class DatabaseTask extends Runnable , CancellationHandler {
@ Override
public void run () {
// perform computation with datasource
}
@ Override
public void onCancel () {
try {
datasource . close ();
} catch ( Exception e ) {
throw new IllegalStateException ( e );
}
}
}
DeferredFutureTask < X > task = new DeferredFutureTask ( new DatabaseTask ());
dm . when ( task ). done (...)
Sie können beispielsweise auch den CancellationHandler
als zusätzliches Argument übergeben
final DataSource datasource = ...;
class DatabaseTask extends Runnable {
@ Override
public void run () {
// perform computation with datasource
}
}
class DatabaseCancellationHandler implements CancellationHandler {
@ Override
public void onCancel () {
try {
datasource . close ();
} catch ( Exception e ) {
throw new IllegalStateException ( e );
}
}
}
DeferredFutureTask < X > task = new DeferredFutureTask ( new DatabaseTask (), new DatabaseCancellationHandler ());
dm . when ( task ). done (...)
Sie können es auch problemlos mit Groovy verwenden!
@Grab ( ' org.jdeferred.v2:jdeferred-core:2.0.0 ' )
import org.jdeferred2.*
import org.jdeferred2.impl.*
def deferred = new DeferredObject ()
def promise = deferred . promise()
promise . done { result ->
println " done: $r esult "
} . fail { rejection ->
println " fail: $r ejection "
} . always { state , result , rejection ->
println " always "
}
deferred . resolve( " done " )
Seit 1.1.0-Beta1
jdeferred-android
ist jetzt verfügbar und kann wie alle anderen Android-Bibliotheken eingebunden werden! Es verwendet auch das Android Maven-Plugin und erstellt eine APKLIB-Datei. Wenn Sie das Android Maven-Plugin verwenden, können Sie Abhängigkeiten einschließen:
APKLIB mit Maven:
< dependency >
< groupId >org.jdeferred.v2</ groupId >
< artifactId >jdeferred-android</ artifactId >
< version >${version}</ version >
< type >apklib</ type >
</ dependency >
AAR mit Maven:
Seit 1.2.0-Beta1
< dependency >
< groupId >org.jdeferred.v2</ groupId >
< artifactId >jdeferred-android-aar</ artifactId >
< version >${version}</ version >
< type >aar</ type >
</ dependency >
AAR mit Gradle:
compile 'org.jdeferred.v2:jdeferred-android-aar:${version}'
// or
compile 'org.jdeferred.v2:jdeferred-android-aar:${version}@aar'
Verfügbare Versionen finden Sie im Maven Central Repository.
jdeferred-android
führt eine neue DeferredManager
-Implementierung namens AndroidDeferredManager
ein. AndroidDeferredManager
stellt sicher, dass Rückrufe im UI-Thread und nicht im Hintergrund-Thread ausgeführt werden, damit Rückrufe UI-Aktualisierungen durchführen können. Alternativ können Rückrufe auch AndroidExecutionScopeable
Schnittstelle implementieren, um genau zu steuern, ob der Rückruf im UI-Thread oder im Hintergrund-Thread ausgeführt werden soll.
AndroidDeferredManager
unterstützt auch das neue DeferredAsyncTask
-Objekt. Dieses Objekt basiert auf AsyncTask
von Android.
Wenn Sie Rückrufe immer im Hintergrundthread ausführen müssen, können Sie weiterhin DefaultDeferredManager
verwenden.
Da JDeferred schließlich SLF4J verwendet, können Sie Protokollnachrichten mit slf4j-android
weiterleiten.
Hier ist ein Beispielcode zur Verwendung von JDeferred mit asynchronem Servlet!
@ WebServlet ( value = "/AsyncServlet" , asyncSupported = true )
public class AsyncServlet extends HttpServlet {
private static final long serialVersionUID = 1L ;
private ExecutorService executorService = Executors . newCachedThreadPool ();
private DeferredManager dm = new DefaultDeferredManager ( executorService );
protected void doGet ( HttpServletRequest request ,
HttpServletResponse response ) throws ServletException , IOException {
final AsyncContext actx = request . startAsync ( request , response );
dm . when ( new Callable < String >() {
@ Override
public String call () throws Exception {
if ( actx . getRequest (). getParameter ( "fail" ) != null ) {
throw new Exception ( "oops!" );
}
Thread . sleep ( 2000 );
return "Hello World!" ;
}
}). then ( new DoneCallback < String >() {
@ Override
public void onDone ( String result ) {
actx . getRequest (). setAttribute ( "message" , result );
actx . dispatch ( "/hello.jsp" );
}
}). fail ( new FailCallback < Throwable >() {
@ Override
public void onFail ( Throwable exception ) {
actx . getRequest (). setAttribute ( "exception" , exception );
actx . dispatch ( "/error.jsp" );
}
});
}
}
DeferredManager.StartPolicy.MANAUL
DeferredManager.StartPolicy.MANUAL
.