Guide to JDeferred – JDeferred指南

最后修改: 2017年 9月 6日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

JDeferred is a small Java library (also supports Groovy) used for implementing asynchronous topology without writing boilerplate code. This framework is inspired by the Jquery’s Promise/Ajax feature and Android’s Deferred Object pattern.

JDeferred是一个小型的Java库(也支持Groovy),用于实现异步拓扑结构,而无需编写模板代码。这个框架的灵感来自于Jquery的Promise/Ajax功能和Android的延迟对象模式。

In this tutorial, we’ll show how to use JDeferred and its different utilities.

在本教程中,我们将展示如何使用JDeferred和它的不同工具。

2. Maven Dependency

2.Maven的依赖性

We can start using JDeferred in any application by adding the following dependency into our pom.xml:

我们可以在任何应用程序中开始使用JDeferred,只要在pom.xml中加入以下依赖关系:

<dependency>
    <groupId>org.jdeferred</groupId>
    <artifactId>jdeferred-core</artifactId>
    <version>1.2.6</version>
</dependency>

We can check the latest version of the JDeferred project in the Central Maven Repository.

我们可以在Central Maven Repository中查看JDeferred项目的最新版本。

3. Promises

3.许诺

Let’s have a look at a simple use-case of invoking an error-prone synchronous REST API call and perform some task based on the data returned by the API.

让我们来看看一个简单的用例,即调用一个容易出错的同步REST API调用,并根据API返回的数据执行一些任务。

In simple JQuery, the above scenario can be addressed in the following way:

在简单的JQuery中,上述情况可以通过以下方式解决。

$.ajax("/GetEmployees")
    .done(
        function() {
            alert( "success" );
        }
     )
    .fail(
        function() {
            alert( "error" );
        }
     )
    .always(
        function() {
            alert( "complete" );
        }
    );

Similarly, JDeferred comes with the Promise and Deferred interfaces which register a thread-independent hook on the corresponding object that triggers different customizable action based on that object status.

类似地,JDeferred带有PromiseDeferred接口,在相应的对象上注册一个线程独立的钩子,根据该对象状态触发不同的可定制动作。

Here, Deferred acts as the trigger and the Promise acts as the observer.

这里,Deferred作为触发器,Promise作为观察者。

We can easily create this type of asynchronous workflow:

我们可以轻松地创建这种类型的异步工作流。

Deferred<String, String, String> deferred
  = new DeferredObject<>();
Promise<String, String, String> promise = deferred.promise();

promise.done(result -> System.out.println("Job done"))
  .fail(rejection -> System.out.println("Job fail"))
  .progress(progress -> System.out.println("Job is in progress"))
  .always((state, result, rejection) -> 
    System.out.println("Job execution started"));

deferred.resolve("msg");
deferred.notify("notice");
deferred.reject("oops");

Here, each method has different semantics:

这里,每个方法都有不同的语义。

  • done() – triggers only when the pending actions on the deferred object is/are completed successfully
  • fail() – triggers while some exception is raised while performing pending action/s on the deferred object
  • progress() – triggers as soon as pending actions on the deferred object is/are started to execute
  • always() – triggers regardless of deferred object’s state

By default, a deferred object’s status can be PENDING/REJECTED/RESOLVED. We can check the status using deferred.state() method.

默认情况下,一个递延对象的状态可以是PENDING/REJECTED/RESOLVED。我们可以使用deferred.state()方法检查状态。

Point to note here is that once a deferred object’s status is changed to RESOLVED, we can’t perform reject operation on that object.

这里需要注意的是,一旦一个延迟对象的状态被改变为RESOLVED,我们就不能对该对象执行reject操作。

Similarly, once the object’s status is changed to REJECTED, we can’t perform resolve or notify operation on that object. Any violation will result into an IllegalStateExeption.

同样地,一旦对象的状态被改变为REJECTED,我们就不能对该对象执行resolvenotify操作。任何违规行为都会导致IllegalStateExeption

4. Filters

4.过滤器

Before retrieving the final result, we can perform filtering on the deferred object with DoneFilter.

在检索最终结果之前,我们可以用DoneFilter对递延对象进行过滤。

Once the filtering is done, we’ll get the thread-safe deferred object:

一旦过滤完成,我们将得到线程安全的递延对象。

private static String modifiedMsg;

static String filter(String msg) {
    Deferred<String, ?, ?> d = new DeferredObject<>();
    Promise<String, ?, ?> p = d.promise();
    Promise<String, ?, ?> filtered = p.then((result) > {
        modifiedMsg = "Hello "  result;
    });

    filtered.done(r > System.out.println("filtering done"));

    d.resolve(msg);
    return modifiedMsg;
}

5. Pipes

5.管子

Similar to filter, JDeferred offers the DonePipe interface to perform sophisticated post-filtering actions once the deferred object pending actions are resolved.

与过滤器类似,JDeferred提供DonePipe接口,一旦递延对象的待定行动被解决,就可以执行复杂的过滤后行动。

public enum Result { 
    SUCCESS, FAILURE 
}; 

private static Result status; 

public static Result validate(int num) { 
    Deferred<Integer, ?, ?> d = new DeferredObject<>(); 
    Promise<Integer, ?, ?> p = d.promise(); 
    
    p.then((DonePipe<Integer, Integer, Exception, Void>) result > {
        public Deferred<Integer, Exception, Void> pipeDone(Integer result) {
            if (result < 90) {
                return new DeferredObject<Integer, Exception, Void>()
                  .resolve(result);
            } else {
                return new DeferredObject<Integer, Exception, Void>()
                  .reject(new Exception("Unacceptable value"));
            }
    }).done(r > status = Result.SUCCESS )
      .fail(r > status = Result.FAILURE );

    d.resolve(num);
    return status;
}

Here, based on the value of the actual result, we’ve raised an exception to reject the result.

在这里,根据实际结果的值,我们提出了一个异常来拒绝这个结果。

6. Deferred Manager

6.递延的经理人

In a real time scenario, we need to deal with the multiple deferred objects observed by multiple promises. In this scenario, it’s pretty difficult to manage multiple promises separately.

在一个实时场景中,我们需要处理由多个承诺观察到的多个延迟对象。在这种情况下,单独管理多个承诺是相当困难的。

That’s why JDeferred comes with DeferredManager interface which creates a common observer for all of the promises. Hence, using this common observer, we can create common actions for all of the promises:

这就是为什么JDeferred带有DeferredManager接口,为所有的承诺创建一个共同的观察者。因此,使用这个共同的观察者,我们可以为所有的承诺创建共同的行动。

Deferred<String, String, String> deferred = new DeferredObject<>();
DeferredManager dm = new DefaultDeferredManager();
Promise<String, String, String> p1 = deferred.promise(), 
  p2 = deferred.promise(), 
  p3 = deferred.promise();
dm.when(p1, p2, p3)
  .done(result -> ... )
  .fail(result -> ... );
deferred.resolve("Hello Baeldung");

We can also assign ExecutorService with a custom thread pool to the DeferredManager:

我们还可以将带有自定义线程池的ExecutorService分配给DeferredManager

ExecutorService executor = Executors.newFixedThreadPool(10);
DeferredManager dm = new DefaultDeferredManager(executor);

In fact, we can completely ignore the use of Promise and can directly define the Callable interface to complete the task:

事实上,我们可以完全忽略Promise的使用,可以直接定义Callable接口来完成这个任务。

DeferredManager dm = new DefaultDeferredManager();
dm.when(() -> {
    // return something and raise an exception to interrupt the task
}).done(result -> ... )
  .fail(e -> ... );

7. Thread-Safe Action

7.螺纹安全行动

Although, most of the time we need to deal with asynchronous workflow, some of the time we need to wait for the results of the all of the parallel tasks.

虽然,大多数时候我们需要处理异步工作流,但有些时候我们需要等待所有并行任务的结果。

In this type of scenario, we may only use Object‘s wait() method to wait for all deferred tasks to finish:

在这种情况下,我们只能使用Objectwait()方法来等待所有推迟的任务完成

DeferredManager dm = new DefaultDeferredManager();
Deferred<String, String, String> deferred = new DeferredObject<>();
Promise<String, String, String> p1 = deferred.promise();
Promise<String, String, String> p = dm
  .when(p1)
  .done(result -> ... )
  .fail(result -> ... );

synchronized (p) {
    while (p.isPending()) {
        try {
            p.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

deferred.resolve("Hello Baeldung");

Alternatively, we can use Promise interface’s waitSafely() method to achieve the same.

另外,我们可以使用Promise接口的waitSafely()方法来实现。

try {
    p.waitSafely();
} catch (InterruptedException e) {
    e.printStackTrace();
}

Although both of the above methods perform pretty much the same thing, it’s always advisable to use the second one since the second procedure doesn’t require synchronization.

虽然上述两种方法的作用基本相同,但总是建议使用第二个方法,因为第二个过程不需要同步。

8. Android Integration

8.安卓系统集成

JDeferred can be easily integrated with Android applications using the Android Maven plugin.

JDeferred可以使用Android Maven插件轻松与Android应用程序集成。

For APKLIB build, we need to add the following dependency in the pom.xml:

对于APKLIB构建,我们需要在pom.xml中添加以下依赖关系。

<dependency>
    <groupId>org.jdeferred</groupId>
    <artifactId>jdeferred-android</artifactId>
    <version>1.2.6</version>
    <type>apklib</type>
</dependency>

For AAR build, we need to add the following dependency in the pom.xml:

对于AAR构建,我们需要在pom.xml中添加以下依赖性。

<dependency>
    <groupId>org.jdeferred</groupId>
    <artifactId>jdeferred-android-aar</artifactId>
    <version>1.2.6</version>
    <type>aar</type>
</dependency>

9. Conclusion

9.结论

In this tutorial, we explored about JDeferred, and it’s different utilities.

在本教程中,我们探讨了JDeferred,以及它的不同功用。

As always, the full source code is available over on GitHub.

一如既往,完整的源代码可在GitHub上获得