JDeferred adalah perpustakaan Java Deferred/Promise yang mirip dengan Objek Deferred JQuery.
Terinspirasi oleh JQuery dan Android Deferred Object.
Jika Anda menggunakan JDeferred 1.x, lihat Dokumentasi 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}'
Temukan versi yang tersedia di Maven Central Repository.
Laporan kompatibilitas antar versi:
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 ) {
...
}
});
Dengan referensi ke objek yang ditangguhkan, Anda kemudian dapat memicu tindakan/pembaruan:
deferred . resolve ( "done" );
deferred . reject ( "oops" );
deferred . notify ( "100%" );
Gunakan
.filter(...)
alih-alih.then(...)
sejak 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.
Gunakan
.pipe(...)
alih-alih.then(...)
sejak 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 (…)
Anda juga dapat menentukan Layanan Pelaksana untuk kebutuhan Anda.
DeferredManager dm = new DefaultDeferredManager(myExecutorService);
Anda dapat menggunakan Callable dan Runnable hampir seperti Promise tanpa pekerjaan tambahan apa pun.
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 ) {
...
}
});
Jika Anda perlu memberi tahu kemajuan dalam Callable atau Runnable, Anda perlu membuat objek Deferred dan Promise Anda sendiri, atau Anda dapat menggunakan DeferredCallable dan DeferredRunnable.
Gunakan objek Ditangguhkan Anda sendiri
final Deferred deferred = ...
Promise promise = deferred . promise ();
promise . then (…);
Runnable r = new Runnable () {
public void run () {
while (…) {
deferred . notify ( myProgress );
}
deferred . resolve ( "done" );
}
}
Atau, memperluas DeferredRunnable
DeferredManager dm = …;
dm . when ( new DeferredRunnable < Double >(){
public void run () {
while (…) {
notify ( myProgress );
}
}
}). then (…);
Sejak 1.0.1
Biasanya, saat menggunakan kerangka kerja ini, Anda ingin melakukan berbagai hal secara asinkron. Namun, jika Anda harus menunggu hingga semua tugas yang ditangguhkan selesai, Anda dapat menggunakan metode Object.wait atau Promise.waitSafely.
Promise p = dm . when (...)
. done (...)
. fail (...)
synchronized ( p )
while ( p . isPending ()) {
try {
p . wait ();
} catch ( InterruptedException e ) { ... }
}
}
Alternatifnya, Anda dapat menggunakan pintasan yang lebih sederhana
Promise p = dm . when (...)
. done (...)
. fail (...)
try {
p . waitSafely ();
} catch ( InterruptedException e ) {
...
}
Ini cukup keren bila digunakan dengan 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 ()))
);
Panggilan ke when
dengan beberapa argumen menghasilkan Promise
bahwa sinyal fail
pada penolakan pertama atau sinyal done
dengan semua nilai yang dihitung.
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!" ));
Sejak 2.0.0
Panggilan ke when
dengan beberapa argumen (hingga lima) akan menghasilkan hasil dengan pengambil yang aman untuk mengetik.
Sejak 2.0.0
Panggilan untuk race
dengan banyak argumen menghasilkan Promise
bahwa sinyal fail
pada penolakan pertama atau sinyal done
pada resolusi pertama.
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!" ));
Sejak 2.0.0
Seruan untuk settle
dengan berbagai argumen menghasilkan Promise
yang mengumpulkan semua resolusi dan penolakan.
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 );
});
Sejak 2.0.0
Terkadang suatu tugas mungkin dibatalkan saat sedang berjalan dan memerlukan pembersihan sumber daya apa pun yang mungkin telah dialokasikan. Anda dapat menentukan tugas yang mengimplementasikan antarmuka org.jdeferred2.CancellationHandler
atau meneruskan argumen tambahan ke DeferredFutureTask
dengan implementasi tersebut, misalnya
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 (...)
Anda juga dapat meneruskan CancellationHandler
sebagai argumen tambahan, misalnya
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 (...)
Anda juga dapat dengan mudah menggunakannya dengan 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 " )
Sejak 1.1.0-Beta1
jdeferred-android
sekarang tersedia, dan dapat dimasukkan sama seperti perpustakaan Android lainnya! Itu juga menggunakan plugin Android Maven dan membuat file apklib. Jika Anda menggunakan plugin Android Maven, Anda dapat menyertakan ketergantungan:
APKLIB dengan Maven:
< dependency >
< groupId >org.jdeferred.v2</ groupId >
< artifactId >jdeferred-android</ artifactId >
< version >${version}</ version >
< type >apklib</ type >
</ dependency >
AAR dengan Maven:
Sejak 1.2.0-Beta1
< dependency >
< groupId >org.jdeferred.v2</ groupId >
< artifactId >jdeferred-android-aar</ artifactId >
< version >${version}</ version >
< type >aar</ type >
</ dependency >
AAR dengan Gradle:
compile 'org.jdeferred.v2:jdeferred-android-aar:${version}'
// or
compile 'org.jdeferred.v2:jdeferred-android-aar:${version}@aar'
Temukan versi yang tersedia di Maven Central Repository.
jdeferred-android
memperkenalkan implementasi DeferredManager
baru yang disebut AndroidDeferredManager
. AndroidDeferredManager
memastikan bahwa callback dijalankan di UI Thread, bukan di Thread latar belakang, agar callback dapat melakukan pembaruan UI. Alternatifnya, callback juga dapat mengimplementasikan antarmuka AndroidExecutionScopeable
untuk mengontrol secara detail apakah callback harus dijalankan di UI Thread atau Thread latar belakang.
AndroidDeferredManager
juga mendukung objek DeferredAsyncTask
baru. Objek ini didasarkan pada AsyncTask
Android.
Jika Anda harus selalu menjalankan callback di thread latar belakang, Anda dapat terus menggunakan DefaultDeferredManager
.
Terakhir, karena JDeferred menggunakan SLF4J - Anda dapat merutekan pesan log lebih lanjut menggunakan slf4j-android
.
Berikut adalah contoh kode cara menggunakan JDeferred dengan Asynchronous 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
sebagai gantinya.