JDeferred 是一個 Java Deferred/Promise 函式庫,類似 JQuery 的 Deferred Object。
受到 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%" );
從 2.0.0-Beta2 開始使用
.filter(...)
代替.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.
從 2.0.0-Beta2 開始使用
.pipe(...)
代替.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 (…)
您也可以根據需要指定執行程序服務。
DeferredManager dm = new DefaultDeferredManager(myExecutorService);
您幾乎可以像使用 Promise 一樣使用 Callable 和 Runnable,而無需任何額外的工作。
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
將產生具有類型安全 getter 的結果。
從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-Beta1 起
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-Beta1 起
< 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
確保回呼在 UI 執行緒而不是後台執行緒中執行,以便回呼進行 UI 更新。或者,回呼還可以實作AndroidExecutionScopeable
接口,以細粒度控制回呼是否應在 UI 執行緒或後台執行緒中執行。
AndroidDeferredManager
也支援新的DeferredAsyncTask
物件。該物件基於 Android 的AsyncTask
。
如果您需要始終在背景執行緒中執行回調,那麼您可以繼續使用DefaultDeferredManager
。
最後,因為 JDeferred 使用 SLF4J - 您可以使用slf4j-android
進一步路由日誌訊息。
以下是有關如何將 JDeferred 與非同步 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
。