JDeferred — это библиотека Java Deferred/Promise, похожая на Deferred Object JQuery.
Вдохновлен JQuery и отложенным объектом Android.
Если вы используете JDeferred 1.x, см. документацию JDeferred 1.x.
.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}'
Найдите доступные версии в центральном репозитории Maven.
Отчеты о совместимости между версиями:
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 ) {
...
}
});
С помощью ссылки на отложенный объект вы можете запускать действия/обновления:
deferred . resolve ( "done" );
deferred . reject ( "oops" );
deferred . notify ( "100%" );
Используйте
.filter(...)
вместо.then(...)
начиная с версии 2.0.0-Beta2.
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.
Используйте
.pipe(...)
вместо.then(...)
начиная с версии 2.0.0-Beta2.
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 (…)
Вы также можете указать Службу Исполнителя для своих нужд.
DeferredManager dm = new DefaultDeferredManager(myExecutorService);
Вы можете использовать Callable и Runnable почти как Promise без какой-либо дополнительной работы.
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 ) {
...
}
});
Если вам нужно уведомлять о прогрессе в вашем Callable или Runnable, вам нужно либо создать свой собственный объект Deferred и Promise, либо вы можете использовать DeferredCallable и DeferredRunnable.
Используйте свой собственный отложенный объект
final Deferred deferred = ...
Promise promise = deferred . promise ();
promise . then (…);
Runnable r = new Runnable () {
public void run () {
while (…) {
deferred . notify ( myProgress );
}
deferred . resolve ( "done" );
}
}
Или расширение DeferredRunnable
DeferredManager dm = …;
dm . when ( new DeferredRunnable < Double >(){
public void run () {
while (…) {
notify ( myProgress );
}
}
}). then (…);
С версии 1.0.1
Обычно при использовании этой платформы вам нужно делать что-то асинхронно. Однако если необходимо дождаться завершения всех отложенных задач, вы можете использовать методы Object.wait или Promise.waitSafely.
Promise p = dm . when (...)
. done (...)
. fail (...)
synchronized ( p )
while ( p . isPending ()) {
try {
p . wait ();
} catch ( InterruptedException e ) { ... }
}
}
Альтернативно вы можете использовать более упрощенный ярлык
Promise p = dm . when (...)
. done (...)
. fail (...)
try {
p . waitSafely ();
} catch ( InterruptedException e ) {
...
}
Это очень круто при использовании с Java 8 Lambda!
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 ()))
);
Вызов when
с несколькими аргументами приводит к Promise
, что сигналы fail
при первом отклонении, или сигналы 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!" ));
С версии 2.0.0
Вызов when
с несколькими аргументами (до пяти) приведет к получению результатов с типобезопасными геттерами.
С версии 2.0.0
Вызовы race
с несколькими аргументами приводят к Promise
, что сигналы fail
при первом отклонении или сигналы 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!" ));
С версии 2.0.0
Вызовы settle
с несколькими аргументами приводят к созданию Promise
, который собирает все разрешения и отклонения.
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 );
});
С версии 2.0.0
Иногда задача может быть отменена во время ее выполнения и потребует очистки всех выделенных ей ресурсов. Вы можете определить задачу, реализующую интерфейс org.jdeferred2.CancellationHandler
, или передать дополнительный аргумент в DeferredFutureTask
с такой реализацией, например
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 (...)
Вы также можете передать CancellationHandler
в качестве дополнительного аргумента, например
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 (...)
Вы также можете легко использовать Groovy!
@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 " )
Начиная с версии 1.1.0-бета1
jdeferred-android
теперь доступен, и его можно включить, как и любую другую библиотеку Android! Он также использует плагин Android Maven и создает файл apklib. Если вы используете плагин Android Maven, вы можете включить зависимость:
APKLIB с Maven:
< dependency >
< groupId >org.jdeferred.v2</ groupId >
< artifactId >jdeferred-android</ artifactId >
< version >${version}</ version >
< type >apklib</ type >
</ dependency >
AAR с Maven:
Начиная с версии 1.2.0-бета1
< dependency >
< groupId >org.jdeferred.v2</ groupId >
< artifactId >jdeferred-android-aar</ artifactId >
< version >${version}</ version >
< type >aar</ type >
</ dependency >
AAR с Gradle:
compile 'org.jdeferred.v2:jdeferred-android-aar:${version}'
// or
compile 'org.jdeferred.v2:jdeferred-android-aar:${version}@aar'
Найдите доступные версии в центральном репозитории Maven.
jdeferred-android
представляет новую реализацию DeferredManager
под названием AndroidDeferredManager
. AndroidDeferredManager
гарантирует, что обратные вызовы выполняются в потоке пользовательского интерфейса, а не в фоновом потоке, чтобы обратные вызовы могли выполнять обновления пользовательского интерфейса. Альтернативно, обратные вызовы также могут реализовывать интерфейс AndroidExecutionScopeable
для детального управления тем, должен ли обратный вызов выполняться в потоке пользовательского интерфейса или в фоновом потоке.
AndroidDeferredManager
также поддерживает новый объект DeferredAsyncTask
. Этот объект основан на Android AsyncTask
.
Если вам нужно всегда выполнять обратные вызовы в фоновом потоке, вы можете продолжать использовать DefaultDeferredManager
.
Наконец, поскольку JDeferred использует SLF4J, вы можете дополнительно маршрутизировать сообщения журнала с помощью slf4j-android
.
Вот пример кода использования JDeferred с асинхронным сервлетом!
@ 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
.