从p:remoteCommand的oncomplete处理程序调用JavaScript函数 - 使用一些JavaScript代码模拟相同的函数 [英] Invoking a JavaScript function from oncomplete handler of p:remoteCommand - simulating the same using some JavaScript code

查看:59
本文介绍了从p:remoteCommand的oncomplete处理程序调用JavaScript函数 - 使用一些JavaScript代码模拟相同的函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

警告:虽然这个问题涵盖了包含大量Java代码片段的长文本信息,但它只是针对JavaScript / jQuery和一些PrimeFaces的东西(只是 < p:remoteCommand> )as as在开头的介绍部分中提到。

Caution : Although this question covers long textual information with a mess of Java code snippets, it is merely targeted to JavaScript/jQuery and a bit of PrimeFaces stuff (just <p:remoteCommand>) as mentioned in the introductory part in the beginning.

我收到来自WebSockets的JSON消息(Java EE 7 / JSR 356) WebSocket API)如下。

I am receiving a JSON message from WebSockets (Java EE 7 / JSR 356 WebSocket API) as follows.

if (window.WebSocket) {
    var ws = new WebSocket("wss://localhost:8181/ContextPath/AdminPush");

    ws.onmessage = function (event) {
        jsonMsg=event.data;
        var json = JSON.parse(jsonMsg);        
        var msg=json["jsonMessage"];

        if (window[msg]) {
            window[msg](); //It is literally interpreted as a function - updateModel();
        }
    };
}

在上面的代码中, event.data 包含一个JSON字符串 {jsonMessage:updateModel} 。因此, msg 将包含一个字符串值 updateModel

In the above code, event.data contains a JSON string {"jsonMessage":"updateModel"}. Thus, msg will contain a string value which is updateModel.

在以下代码段中,

if (window[msg]) {
    window[msg](); //It is literally interpreted as a JavaScript function - updateModel();
}

window [msg](); 导致调用与< p:remoteCommand> 相关联的JavaScript函数(后者又调用 actionListener =#{ bean.remoteAction}< p:remoteCommand> 相关联。)

window[msg](); causes a JavaScript function associated with a <p:remoteCommand> to be invoked (which in turn invokes an actionListener="#{bean.remoteAction}" associated with the <p:remoteCommand>).

<p:remoteCommand name="updateModel"
                 actionListener="#{bean.remoteAction}" 
                 oncomplete="notifyAll()"
                 process="@this"
                 update="@none"/>

update =@ none不一定需要。

update="@none" is not necessarily needed.

收到此消息后,我需要通知所有关联的客户这个更新。我使用以下JavaScript函数来执行此操作,该函数与上述< p:remoteCommand> oncomplete 处理程序相关联>。

After receiving this message, I need to notify all the associated clients about this update. I use the following JavaScript function to do so which is associated with the oncomplete handler of the above <p:remoteCommand>.

var jsonMsg;

function notifyAll() {
    if(jsonMsg) {
       sendMessage(jsonMsg);
    }
}

请注意变量 jsonMsg 已在第一个片段中分配了一个值 - 它是一个全局变量。 sendMessage()是另一个JavaScript函数,它实际上通过WebSockets向所有关联的客户端发送有关此更新的通知,这个问题不需要。

Notice that the variable jsonMsg is already assigned a value in the first snippet - it is a global variable. sendMessage() is another JavaScript function that actually sends a notification about this update to all the associated clients through WebSockets which is not needed in this question.

这种方法效果很好但是有一种方法可以在以下条件下做一些魔术

This works well but is there a way to do some magic in the following condition

if (window[msg]) {
    window[msg]();

    //Do something to call notifyAll() on oncomplete of remote command.
}

以便 notifyAll()函数可以直接通过一些JavaScript代码调用(目前附加到 oncomplete < p:remoteCommand> 和预期的JavaScript代码(甚至其他东西)应该模拟这个 oncomplete )基本上不需要依赖全局JavaScript变量( jsonMSg )?

so that the notifyAll() function can be invoked through some JavaScript code directly (which is currently attached to oncomplete of <p:remoteCommand> and the expected JavaScript code (or even something else) should simulate this oncomplete) basically eliminating the need to depend upon a global JavaScript variable (jsonMSg)?

例如,当管理员对一个名为 Category的JPA实体进行一些更改(通过DML操作),触发实体侦听器,这反过来导致CDI事件如下所示。

When an admin for example, makes some changes (by means of DML operations) to a JPA entity named Category, entity listeners are triggered which in turn causes a CDI event to be raised as follows.

@ApplicationScoped
public class CategoryListener {

    @PostPersist
    @PostUpdate
    @PostRemove
    public void onChange(Category category) throws NamingException {
        BeanManager beanManager = (BeanManager) InitialContext.doLookup("java:comp/BeanManager");
        beanManager.fireEvent(new CategoryChangeEvent(category));
    }
}

不用说实体类别使用注释 @EntityListeners(CategoryListener.class)指定。

Needless to say that the entity Category is designated with the annotation @EntityListeners(CategoryListener.class).

只是旁注(完全偏离主题):通过JNDI查找获取 BeanManager 的实例,如前面的代码所示片段是暂时的。具有Weld版本2.2.2 final的GlassFish Server 4.1无法注入CDI事件 javax.enterprise.event.Event< T> ,它应该按如下方式注入。

Just one side note (completely off topic) : Getting an instance of BeanManager through a JNDI look-up as done in the preceding code snippet is temporary. The GlassFish Server 4.1 having the Weld version 2.2.2 final fails to inject the CDI event javax.enterprise.event.Event<T> which is supposed to be injected as follows.

@Inject
private Event<CategoryChangeEvent> event;

然后,参考上面的相关代码片段,可以按照以下方式触发事件。

And then, the event can be fired as follows with reference to the relevant code snippet above.

event.fire(new CategoryChangeEvent(category));

在Web项目中观察到此事件如下。

This event is observed in the web project as follows.

@ApplicationScoped
public class RealTimeUpdate {

    public void onCategoryChange(@Observes CategoryChangeEvent event) {
        AdminPush.sendAll("updateModel");
    }
}

管理员使用自己的终点如下( AdminPush.sendAll(updateModel); 在其中手动调用)。

Where an admin uses his own end-point as follows (AdminPush.sendAll("updateModel"); is invoked manually therein).

@ServerEndpoint(value = "/AdminPush", configurator = ServletAwareConfig.class)
public final class AdminPush {

    private static final Set<Session> sessions = new LinkedHashSet<Session>();

    @OnOpen
    public void onOpen(Session session, EndpointConfig config) {
        if (Boolean.valueOf((String) config.getUserProperties().get("isAdmin"))) {
            sessions.add(session);
        }
    }

    @OnClose
    public void onClose(Session session) {
        sessions.remove(session);
    }

    private static JsonObject createJsonMessage(String message) {
        return JsonProvider.provider().createObjectBuilder().add("jsonMessage", message).build();
    }

    public static void sendAll(String text) {
        synchronized (sessions) {
            String message = createJsonMessage(text).toString();
            for (Session session : sessions) {
                if (session.isOpen()) {
                    session.getAsyncRemote().sendText(message);
                }
            }
        }
    }
}

此处只允许管理员使用此终点。使用 onOpen()方法中的条件检查阻止所有其他用户创建WebSocket会话。

Here only an admin is allowed to use this end-point. All other users are prevented from creating a WebSocket session using a conditional check in the onOpen() method.

session.getAsyncRemote()。sendText(message); foreach 循环中发送通知(以JSON的形式)消息)管理员关于在实体类别中进行的这些更改。

session.getAsyncRemote().sendText(message); inside the foreach loop sends a notification (in the form of a JSON message) to the admin about these changes made in the entity Category.

如第一个代码片段所示, window [msg](); 调用一个动作方法(通过< p:remoteCommand> ,如前所示)与应用程序作用域bean相关联 - actionListener =#{realTimeMenuManagedBean.remoteAction}

As shown in the first code snippet, window[msg](); invokes an action method (through a <p:remoteCommand> as shown earlier) associated with an application scoped bean - actionListener="#{realTimeMenuManagedBean.remoteAction}".

@Named
@ApplicationScoped
public class RealTimeMenuManagedBean {

    @Inject
    private ParentMenuBeanLocal service;

    private List<Category> category;
    private final Map<Long, List<SubCategory>> categoryMap = new LinkedHashMap<Long, List<SubCategory>>();
    // Other lists and maps as and when required for a dynamic CSS menu.

    public RealTimeMenuManagedBean() {}

    @PostConstruct
    private void init() {
        populate();
    }

    private void populate() {
        categoryMap.clear();
        category = service.getCategoryList();

        for (Category c : category) {
            Long catId = c.getCatId();
            categoryMap.put(catId, service.getSubCategoryList(catId));
        }
    }

    // This method is invoked through the above-mentioned <p:remoteCommand>.
    public void remoteAction() {
        populate();
    }

    // Necessary accessor methods only.
}

所有其他用户/客户(在不同的面板上 - 除了管理面板之外)只应在 actionListener =#{realTimeMenuManagedBean.remoteAction}完全完成时通知 - 在操作方法完成之前不得发生 - 应该是通过 oncomplate 事件处理程序通知< p:remoteCommand> 这就是为什么两个已经采取了不同的终点。

All other users/clients (who are on a different panel - other than the admin panel) should only be notified when actionListener="#{realTimeMenuManagedBean.remoteAction}" finishes in its entirely - must not happen before the action method finishes - should be notified through the oncomplate event handler of <p:remoteCommand>. This is the reason why two different end-points have been taken.

其他用户使用他们自己的终点:

Those other users use their own end-point:

@ServerEndpoint("/Push")
public final class Push {

    private static final Set<Session> sessions = new LinkedHashSet<Session>();

    @OnOpen
    public void onOpen(Session session) {
        sessions.add(session);
    }

    @OnClose
    public void onClose(Session session) {
        sessions.remove(session);
    }

    @OnMessage
    public void onMessage(String text) {
        synchronized (sessions) {
            for (Session session : sessions) {
                if (session.isOpen()) {
                    session.getAsyncRemote().sendText(text);
                }
            }
        }
    }
}

当通过 oncomplete 发送消息时,使用 @OnMessage 注释的方法开始播放c $ c>< p:remoteCommand> ,如上所示。

The method annotated with @OnMessage comes to play, when a message is sent through oncomplete of <p:remoteCommand> as shown above.

这些客户端使用以下JavaScript代码从中获取新值上面提到的应用程序作用域bean(管理员已经从数据库中充分查询了bean。因此,没有必要分别由每个单独的客户端(管理员除外)再次查询它。因此,它是一个应用程序范围的bean)。

Those clients use the following JavaScript code to just fetch the new values from the above-mentioned application scoped bean (the bean was already queried adequately by the admin from the database. Thus, there is no need to ridiculously query it again by each and every individual client separately (other than the admin). Hence, it is an application scoped bean).

if (window.WebSocket) {
    var ws = new WebSocket("wss://localhost:8181/ContextPath/Push");
    ws.onmessage = function (event) {
        var json = JSON.parse(event.data);
        var msg = json["jsonMessage"];

        if (window[msg]) {
            window[msg]();
        }
    };

    $(window).on('beforeunload', function () {
        ws.close();
    });
}

结合以下< p:remoteCommand> ;

<p:remoteCommand name="updateModel"
                 process="@this"
                 update="parentMenu"/>

其中 parentMenu - 要更新的组件通过此< p:remoteCommand> 是容器JSF组件的 id < h:panelGroup> 其中包含一个简单的CSS菜单,其中包含一堆< ui:repeat> s。

Where parentMenu - the component to be updated by this <p:remoteCommand> is an id of a container JSF component <h:panelGroup> which contains a plain CSS menu with a bunch of <ui:repeat>s.

希望这会使情况更清晰。

Hope this makes the scenario clearer.

此问题已根据此处 .primefaces.org / showcase / ui / ajax / remoteCommand.xhtmlrel =nofollow noreferrer> < p:remoteCommand> (至于具体的问题,唯一的问题是删除对该问题的介绍部分中所述的全局JavaScript变量的依赖。)

This question has been answered precisely here based on <p:remoteCommand> (As to the concrete question, the sole question was to remove a dependency upon a global JavaScript variable as stated in the introductory part of this question).

推荐答案

我不认为我理解你问题的每个方面,但无论如何我试着帮助一下。请注意,我不知道PrimeFaces,所以我所做的就是阅读文档。

I don't think I understood every aspect of your problem, but anyway I try to help a bit. Note that I do not know PrimeFaces, so all I did was reading the docs.

我的理解是,你试图摆脱全局变量。但我担心,我不认为这是可能的。

What I understand is, that you try to get rid of the global variable. But I am afraid, I do not think this is possible.

问题在于,PrimeFaces不允许您通过调用远程调用透明地传递某些内容进一步到 oncomplete 调用(除了你把它传递给Bean的Java代码然后再回到UI,这通常不是你想要的)。

The problem here is, that PrimeFaces does not allow you to pass something transparently from your invocation of the remote call further to the oncomplete call (except you pass it to a Java code of the Bean and then back to the UI, and this usually is not what you want).

但是,我希望,你可以非常接近它。

However, I hope, you can come very close to it.

请注意,可能存在一些关于Java和JavaScript的误解。

Please also note that there probably is some misconception about Java and JavaScript.

Java是多线程的,并行运行多个命令, JavaScript是单线程的,通常永远不会等待完成某些事情。为了获得响应式Web-UI,必须以异步方式执行操作。

Java is multithreaded and runs several commands in parallel, while JavaScript is singlethreaded and usually never waits for something to complete. Doing things asychronously is mandatory to get a responsive Web-UI.

因此您的 remoteCommand 调用(从JS看到) ()(通常是异步大小写)将在 oncomplete 处理程序被调用之前返回很久。这意味着,如果 window [msg]()返回,那么你还没有完成 remoteCommand

Hence your remoteCommand invocation (seen from the JS side) will (usually, async case) return long before the oncomplete handler will be invoked. That means, if window[msg]() returns, you are not finished with the remoteCommand yet.

那么你想用以下代码管理什么

So what you want to manage with following code

if (window[msg]) {
    window[msg]();

    //Do something to call notifyAll() on oncomplete of remote command.
    dosomethinghere();
}

将失败。返回 remoteCommand 时,不会调用 dosomethinghere()(因为JS不想等待某个事件,可能永远不会发生)。这意味着,当Ajax请求刚刚打开到远程(到Java应用程序)时,将调用 dosomethinghere()

will fail. dosomethinghere() will not be invoked when the remoteCommand returned (as JS does not want to wait for some event, which might never happen). This means, dosomethinghere() will be invoked when the Ajax-request was just opened to the remote (to the Java application).

要在Ajax调用完成后运行一些东西,必须在 oncomplete 例程中完成(或 onsuccess )。这就是它的原因。

To run something after the Ajax call finished, this must be done in the oncomplete routine (or onsuccess). This is why it's there.

请注意与窗口[msg]()不同的内容。如果您不能完全信任推送的消息,则可以认为这有点危险。 window [msg]()基本上运行任何以变量 msg 的内容命名的函数。例如,如果 msg 恰好是关闭,那么 window.close()将会运行,这可能不是你想要的。

Please note something different about window[msg](). This can be considered a bit dangerous if you cannot trust the pushed message completely. window[msg]() essentially runs any function named with the contents of the variable msg. For example if msg happen to be close then window.close() will be run, which probably is not what you want.

你应该确定, msg 是一个预期的词,并拒绝所有其他的话。示例代码:

You should make sure, msg is one expected word, and decline all other words. Example code for this:

var validmsg = { updateModel:1, rc:1 }

[..]

if (validmsg[msg] && window[msg])
  window[msg]();



第3部分:如何并行处理多条JSON消息



全局变量有一些缺点。只有一个。如果您碰巧在WebSocket上收到另一条JSON消息,而前一条消息仍在 remoteCommand 中处理,则会覆盖以前的消息。所以 notifyAll()会看到两次较新的消息,旧消息会丢失。

Part 3: How to handle multiple JSON messages in parallel

The global variable has some drawback. There is only one. If you happen to receive another JSON message on the WebSocket while the previous message still is processing in the remoteCommand, this will overwrite the previous message. So the notifyAll() will see the newer message twice, the old one is lost.

一个典型的竞争条件。您必须做的是,创建类似注册表的东西来注册所有消息,然后将一些值传递给 notifyAll()告诉,哪些注册消息应该是经过处理。

A classical race condition. What you must do is, to create something like a registry to register all the messages, and then pass some value to notifyAll() to tell, which of the registered messages shall be processed.

只需稍加改动,您就可以并行(此处)或连续(第4部分)处理消息。

With only a little change, you can either parallely (here) or serially (Part 4) process the messages.

首先,创建一个计数器以区分消息。也是存储所有消息的对象。我们声明了我们期望的所有有效消息(参见第2部分):

First, create a counter to be able to distinguish the messages. Also an object to store all the messages. And we declare all valid messages we expect (see Part 2):

var jsonMsgNr = 0;
var jsonMessages = {};
var validmsg = { updateModel:1 }

现在我们收到一条消息:

Now add a message each time we receive one:

if (window.WebSocket) {
    var ws = new WebSocket("wss://localhost:8181/ContextPath/AdminPush");

    ws.onmessage = function (event) {
        var jsonMsg = event.data;
        var json = JSON.parse(jsonMsg);        
        var msg=json["jsonMessage"];

        if (validmsg[msg] && window[msg]) {
            var nr = ++jsonMsgNr;
            jsonMessages[nr] = { jsonMsg:jsonMsg, json:json };

能够将 nr 传递给 NotifyAll()需要将另一个参数传递给Bean。我们称之为 msgNr

To be able to pass the nr to NotifyAll() an additional parameter needs to be passed to the Bean. Let's call it msgNr:

            // Following might look a bit different on older PrimeFaces
            window[msg]([{name:'msgNr', value:nr}]);
        }
    }
}

或许看看< a href =https://stackoverflow.com/a/7221579/490291> https://stackoverflow.com/a/7221579/490291 了解更多关于以这种方式传递值的信息。

Perhaps have a look into https://stackoverflow.com/a/7221579/490291 for more on passing values this way.

remoteAction bean现在获得了一个额外的参数 msgNr ,必须通过通过Ajax返回。

The remoteAction bean now gets an additional parameter msgNr passed, which must be passed back via Ajax.


不幸的是,我不知道(对不起)这在Java中看起来如何。所以请确保,你对AjaxCall的回答再次将 msgNr 复制出去。

另外,因为文档很安静关于这个主题,我不确定如何将参数传递回 oncomplete 处理程序。根据JavaScript调试器, notifyAll()获取3个参数: xhdr payload pfArgs 。不幸的是我无法设置测试用例以了解事情的样子。

Also, as the documentation is quiet about this subject, I am not sure how the parameters are passed back to the oncomplete handler. According to the JavaScript debugger, notifyAll() gets 3 parameters: xhdr, payload, and pfArgs. Unfortunately I was not able to setup a test case to find out how things look like.

因此该函数看起来有点像(熊)和我在一起):

Hence the function looks a bit like (bear with me, please):

function notifyAll(x, data, pfArgs) {
   var nr = ???; // find out how to extract msgNr from data

   var jsonMsg = jsonMessages[nr].jsonMsg;
   var json = jsonMessages[nr].json;
   jsonMessages[nr] = null;  // free memory

   sendMessage(jsonMsg);

   dosomething(json);
}

如果将其拆分为两个函数,则可以调用 notifyAll()来自您应用程序的其他部分:

If you split this into two functions, then you can invoke the notifyAll() from other parts in your application:

function notifyAll(x, data, unk) {
   var nr = ???; // find out how to extract msgNr from data

   realNotifyAll(nr);
}

function realNotifyAll(nr) {
  if (!(nr in jsonMessages)) return;

  var jsonMsg = jsonMessages[nr].jsonMsg;
  var json = jsonMessages[nr].json;
  delete jsonMessages[nr];  // free memory

  sendMessage(jsonMsg);

  dosomething(json);
}




这里的一些事情有点多余。例如,您可能不需要 jsonMessages 中的 json 元素,或者想要解析 json 再次提供一些内存,以防json非常大。但是,代码不是最佳的,而是易于根据您的需要进行调整。

Some things here are a bit redundant. For example you perhaps do not need the json element in jsonMessages or want to parse the json again to spare some memory in case the json is very big. However the code is meant not to be optimal but to be easy to adjust to your needs.



第4部分:序列化请求



现在对序列化事物进行更改。通过添加一些信号量,这很容易。 JavaScript中的信号量只是变量。这是因为只有一个全局线程。

Part 4: serialize requests

Now to the changes to serialize things. That's quite easy by adding some semaphore. Semaphores in JavaScript are just variables. This is because there is only one global thread.

var jsonMsgNr = 0;
var jsonMessages = {};
var validmsg = { updateModel:1 }
var jsonMsgNrLast = 0;           // ADDED

if (window.WebSocket) {
    var ws = new WebSocket("wss://localhost:8181/ContextPath/AdminPush");

    ws.onmessage = function (event) {
        var jsonMsg = event.data;
        var json = JSON.parse(jsonMsg);        
        var msg=json["jsonMessage"];

        if (validmsg[msg] && window[msg]) {
            var nr = ++jsonMsgNr;
            jsonMessages[nr] = { jsonMsg:jsonMsg, json:json };

            if (!jsonMsgNrLast) {    // ADDED
                jsonMsgNrLast = nr;  // ADDED
                window[msg]([{name:'msgNr', value:nr}]);
            }
        }
    }
}

function realNotifyAll(nr) {
  if (!(nr in jsonMessages)) return;

  var jsonMsg = jsonMessages[nr].jsonMsg;
  var json = jsonMessages[nr].json;
  delete jsonMessages[nr];  // free memory

  sendMessage(jsonMsg);

  dosomething(json);

  // Following ADDED
  nr++;
  jsonMsgNrLast = 0;
  if (nr in jsonMessages)
    {
      jsonMsgNrLast = nr;
      window[jsonMessages[nr].json.msg]([{name:'msgNr', value:nr}]);
    }
}

注意: jsonMsgNrLast 可能只是一个标志(true / false)。但是,在变量中包含当前处理的数字可能对其他地方有帮助。

Note: jsonMsgNrLast could be just a flag (true/false). However having the current processed number in a variable perhaps can help somewhere else.

话虽如此,如果中出现故障,则存在饥饿问题sendMessage dosomething 。所以也许你可以稍微交错:

Having said that, there is a starvation problem in case something fails in sendMessage or dosomething. So perhaps you can interleave it a bit:

function realNotifyAll(nr) {
  if (!(nr in jsonMessages)) return;

  var jsonMsg = jsonMessages[nr].jsonMsg;
  var json = jsonMessages[nr].json;
  delete jsonMessages[nr];  // free memory

  nr++;
  jsonMsgNrLast = 0;
  if (nr in jsonMessages)
    {
      jsonMsgNrLast = nr;
      // Be sure you are async here!
      window[jsonMessages[nr].json.msg]([{name:'msgNr', value:nr}]);
    }

  // Moved, but now must not rely on jsonMsgNrLast:
  sendMessage(jsonMsg);
  dosomething(json);
}

这样,AJAX请求已经发出,而 sendMessage 正在运行。如果现在 dosomething 有JavaScript错误或类似错误,邮件仍然可以正确处理。

This way the AJAX request is already send out while sendMessage is running. If now dosomething has a JavaScript error or similar, the messages are still processed correctly.


<请注意:所有这些都是在没有任何测试的情况下输入的。可能存在语法错误或更糟。对不起,我尽我所能。如果您发现了错误,编辑就是您的朋友。

Please note: All this was typed in without any tests. There might be syntax errors or worse. Sorry, I tried my best. If you find a bug, edit is your friend.



第5部分:从JS直接调用



现在,完成所有这些并进行序列化运行后,您始终可以使用 realNotifyAll(jsonMsgNrLast)调用之前的 notifyAll()。或者您可以在列表中显示 jsonMessages 并选择任意数字。

Part 5: Direct Invocation from JS

Now, with all this in place and a serialized Run, you can always invoke the previous notifyAll() using realNotifyAll(jsonMsgNrLast). Or you can display the jsonMessages in a list and choose any arbitrary number.

跳过对<$的调用c $ c> window [jsonMessages [nr] .json.msg]([{name:'msgNr',value:nr}]); (以上窗口[msg] ]([{name:'msgNr',value:nr}]); )您还可以暂停Bean处理并使用常用的JQuery回调按需运行它。为此创建一个函数并再次更改代码:

By skipping the call to window[jsonMessages[nr].json.msg]([{name:'msgNr', value:nr}]); (and above window[msg]([{name:'msgNr', value:nr}]);) you also can halt the Bean processing and run it on-demand using the usual JQuery callbacks. For this create a function and change the code a bit again:

var jsonMsgNr = 0;
var jsonMessages = {};
var validmsg = { updateModel:1 }
var jsonMsgNrLast = 0;
var autoRun = true;        // ADDED, set false control through GUI

if (window.WebSocket) {
    var ws = new WebSocket("wss://localhost:8181/ContextPath/AdminPush");

    ws.onmessage = function (event) {
        var jsonMsg = event.data;
        var json = JSON.parse(jsonMsg);        

        if (validmsg[msg] && window[msg]) {
            var nr = ++jsonMsgNr;
            jsonMessages[nr] = { jsonMsg:jsonMsg, json:json };

            updateGuiPushList(nr, 1);

            if (autoRun && !jsonMsgNrLast) {
                runRemote(nr);
            }
        }
    }
}

function realNotifyAll(nr) {
  if (!(nr in jsonMessages)) return;

  var jsonMsg = jsonMessages[nr].jsonMsg;
  var json = jsonMessages[nr].json;
  delete jsonMessages[nr];  // free memory

  updateGuiPushList(nr, 0);

  jsonMsgNrLast = 0;
  if (autoRun)
    runRemote(nr+1);

  // Moved, but now must not rely on jsonMsgNrLast:
  sendMessage(jsonMsg);
  dosomething(json);
}

function runRemote(nr) {
  if (nr==jsonMsgNrLast) return;
  if (nr in jsonMessages)
    {
      if (jsonMsgNrLast) { alert("Whoopsie! Please wait until processing finished"); return; }
      jsonMsgNrLast = nr;

      updateGuiPushList(nr, 2);

      // Be sure you are async here!
      window[jsonMessages[nr].json.msg]([{name:'msgNr', value:nr}]);
    }
}

现在你可以用<$ c $开始处理c> runRemote(nr)并使用 realNotifyAll(nr)调用完成函数。

Now you can start the processing with runRemote(nr) and invoke the completion function with realNotifyAll(nr).

函数 updateGuiPushList(nr,state) with state = 0:finished 1 = added 2 = running 是回调您的GUI代码,更新屏幕上等待处理的列表。设置 autoRun = false 以停止自动处理,并设置 autoRun = true 进行自动处理。

The function updateGuiPushList(nr, state) with state=0:finished 1=added 2=running is the callback to your GUI code which updates the on-screen list of waiting pushes to process. Set autoRun=false to stop automatic processing and autoRun=true for automatic processing.

注意:将 autoRun false 设置为 true 当然,你需要用最低的 nr 触发 runRemote

Note: After setting autoRun from false to true you need to trigger runRemote once with the lowest nr, of course.

这篇关于从p:remoteCommand的oncomplete处理程序调用JavaScript函数 - 使用一些JavaScript代码模拟相同的函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆