JDeferred هي مكتبة Java Deferred/Promise تشبه مكتبة JQuery's Deferred Object.
مستوحاة من JQuery وAndroid Deferred Object.
إذا كنت تستخدم 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 Central Repository.
تقارير التوافق بين الإصدارات:
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 تقريبًا مثل الوعد دون أي عمل إضافي.
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 الخاص بك، فأنت بحاجة إما إلى إنشاء كائن مؤجل ووعد خاص بك، أو يمكنك استخدام 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 ()))
);
تؤدي الاستدعاءات التي يتم إجراؤها باستخدام وسائط متعددة Promise
when
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-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 مع مخضرم:
منذ 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 Central Repository.
يقدم jdeferred-android
تطبيقًا جديدًا DeferredManager
يسمى AndroidDeferredManager
. يتأكد AndroidDeferredManager
من تنفيذ عمليات الاسترجاعات في مؤشر ترابط واجهة المستخدم بدلاً من مؤشر ترابط الخلفية حتى تتمكن عمليات الاسترجاعات من إجراء تحديثات لواجهة المستخدم. وبدلاً من ذلك، يمكن لعمليات الاسترجاعات أيضًا تنفيذ واجهة AndroidExecutionScopeable
للتحكم الدقيق فيما إذا كان يجب تنفيذ رد الاتصال في مؤشر ترابط واجهة المستخدم أو مؤشر ترابط الخلفية.
يدعم AndroidDeferredManager
أيضًا كائن DeferredAsyncTask
الجديد. يعتمد هذا الكائن على AsyncTask
الخاص بنظام Android.
إذا كنت بحاجة إلى تنفيذ عمليات الاسترجاعات دائمًا في سلسلة المحادثات الخلفية، فيمكنك الاستمرار في استخدام 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
بدلاً من ذلك.