4

基于这个SO question,我了解到 Wicket 将后续的 AJAX 请求排队。现在我的页面充满了几个 AJAX 请求,我想再添加一个会产生冗长操作的请求。

public void populateItem(final Item item) {
  final MyObject object = (MyObject) item.getModelObject();
  // ... a couple of fields
  Label statusLabel = new Label("status", new AbstractReadOnlyModel() {
    @Override
    public Object getObject() {
      return someService.doSomeLengthyOperation();
    }
  });
  statusLabel.add(new AjaxSelfUpdatingTimerBehavior(Duration.seconds(5)));
  item.add(statusLabel)
}

一旦这个 Ajax 请求触发,它可能需要一分钟才能完成执行。这里的问题是我someService.doSomeLengthyOperation()将执行n times the number of rows,这意味着我将排队n times two-minutes。现在,正如我所提到的,Wicket 将后续的 AJAX 请求排队。

发生的事情是我number-of-rows * minutes-it-take-to-finish-the-operation需要加载页面或执行其他需要 AJAX 的操作,例如

new AjaxButton("ajax-button"){
  @Override
  protected void onSubmit(AjaxRequestTarget target, Form form) {
    //.. this won't be executed until all the statusLabels have finished invoking getObject()
  }
}

我想避免创建一个暴露我的服务的 Web 服务并且不得不编写我自己的 AJAX 调用。我有哪些选择?(使用 Wicket 1.5 / Pax-Wicket)

4

2 回答 2

3

最简单的方法是让初始 Ajax 请求快速返回(没有任何结果)并将AjaxSelfUpdatingTimerBehavior添加到目标组件。如果有结果,则此行为将检查一个间隔(例如每 10 秒左右)。如果有结果,它应该更新组件并删除自己。

这样,您可以在单独的任务中执行操作,而不会阻塞您的 Ajax 调用。

详细说明一下,我创建了一个可运行的快速入门,它发出 5 个 Ajax 调用,如您所描述的,每个调用运行 10 秒到 1 分钟之间的随机时间。同时,还有一个带有计数器的响应式 AjaxLink。

主要思想是将实际的 Ajax 调用与对慢速方法的调用分开。

add(new ListView<DataHolder>("list", list) {

    @Override
    protected void populateItem(ListItem<DataHolder> item) {
        DataHolder dh = item.getModelObject();
        item.add(new Label("itemNumber", new PropertyModel<Integer>(dh, "number")));
        Label result = new Label("itemResult", new PropertyModel<String>(dh, "result"));
        result.setOutputMarkupId(true);
        result.add(new AjaxSelfUpdatingTimerBehavior(Duration.seconds(2)));
        item.add(result);
        Thread thread = new Thread(new Processor(item.getModelObject()));
        thread.start();
    }
});

如您所见,标签模型不再直接调用doSomeLengthyOperation()。相反,会产生一个新的线程来完成繁重的工作。Processor 类仅实现 Runnable 接口并使用 run-method 来完成工作(在您的情况下,在演示中它只是等待一段时间)。

PropertyModel 的 getter 封装了这个特技并使其透明,同时始终快速返回以防止阻塞。

public String getResult() {
    String retValue;
    if (!processed) {
        retValue = String.format("Still busy after %d requests", counter++);
    } else {
        retValue = result;
    }
    return retValue;
}

处理的成员只是一个标志,处理器用来指示它何时完成等待(ehr 工作)。

由于您可能会同时发出超过 5 个线程,我建议使用某种线程池,但这超出了这个小演示的范围。


免责声明:这不是生产代码。这只是为了演示。这对您的资源不利,也不会优雅地处理任何资源不足。当用户点击重新加载或发生其他任何事情时,它将不起作用。

于 2013-03-11T12:45:49.387 回答
0

我不完全确定 WicketStuff Async Task 是否可以帮助您,但请尝试一下:

https://github.com/wicketstuff/core/wiki/Async-tasks

这是 Async Tasks 项目中的简短演示:

public class DemoPage extends WebPage implements IRunnableFactory {

public DemoPage() {

    Form<?> form = new Form<Void>("form");
    AbstractTaskContainer taskContainer = DefaultTaskManager.getInstance()
        .makeContainer(1000L, TimeUnit.MINUTES);
    ProgressButton progressButton = new ProgressButton("button", form, 
        Model.of(taskContainer), this, Duration.milliseconds(500L));
    ProgressBar progressBar = new ProgressBar("bar", progressButton);

    add(form);
    form.add(progressButton);
    form.add(progressBar);
}

@Override
public Runnable getRunnable() {
    return new IProgressObservableRunnable() {
        // Runnable implementation.
    };
}
于 2015-12-17T12:45:36.000 回答