【问题标题】:How to implement the queue of events?如何实现事件队列?
【发布时间】:2011-09-25 09:37:56
【问题描述】:

我需要实现事件队列(=服务器上的更新)。当用户更改滑块、按下按钮等时,新事件将添加到此队列中。每个事件将包含以下属性:

  1. 设备 ID(该操作将应用于服务器上的该设备)
  2. 操作(设置、获取等)
  3. value(应该在操作中使用的值)

应该在最后添加新事件。但是,如果已经有相同设备 ID 和相同操作的事件,则应使用新值更新此事件。我该怎么做?

我已经起草了以下内容:

var inCall = false;
var queueArrayDevices = new Array();
var queueArrayActions = new Array();
var queueArrayValues = new Array();

// add call to the queue, at the end
function addAPICall(device, action, value){
    // should NOT add event here, if device and action already exists
    // should update the value instead
    queueArrayDevices.push(device);
    queueArrayAсtions.push(action);
    queueArrayValues.push(value);
}

function doAPICall(device, action, value){    
    inCall = true;
    // call server here
    // if not successful, we should add this item to the queue again
    inCall = false;
}

function callAPIQueue(){
    if(!inCall && queueArrayDevices.length > 0){
        device = queueArrayDevices.shift();
        action = queueArrayAсtions.shift();
        value = queueArrayValues.shift();
        doAPICall(device, action, value);        
    }
}

// start queue processing
setInterval(callAPIQueue, 400);

我使用jquery mobile,也许它可以帮助我简化这样的队列创建?

【问题讨论】:

    标签: javascript jquery-mobile queue


    【解决方案1】:

    如果您期望事件队列较短,那么@Martin 的解决方案是合适的。他的解决方案的时间复杂度是 O(n),其中 n 是队列长度,如果 n 很小,这是完美的。

    如果您的队列可能会很长,那么您可能会考虑采用如下更快的方法。队列由将唯一标识符(device_id、action)映射到值的映射表示。这提供了对现有属性的快速查找。时间复杂度降低到 O(log n)。 Javascript 中映射的一个方便实现是使用将 (device_id, action) 编码为唯一字符串的对象属性,例如“device_id#action”。此外,属性被链接以提供先进/先出行为。

    var Map = {
        // properties: "id#action": {value: value, next: property}
        first: "",
        last: "",
        empty: function() {return Map.first == "";},
        enque: function(device, action, value) {
            var k = device + "#" + action;
            if (k in Map) {
                Map[k].value = value;
            }
            else {
                Map[k] = {value: value, next: ""};
                if (Map.first == "") {
                    Map.first = Map.last = k;
                }
                else {
                    Map[Map.last].next = k;
                    Map.last = k;
                }               
            }
    
        },
        deque: function() {
            var firstProp = Map.first;
            var key = firstProp.split("#");
            var value = Map[firstProp].value;
            Map.first = Map[firstProp].next;
            delete firstProp; // delete this property
            return {device: key[0], action: key[1], value: value};  
        }   
    };
    

    地图使用如下:

    function addAPICall(device, action, value) {
        Map.enque(device, action, value);
    }    
    function callAPIQueue() {     
        if (!inCall && !Map.empty()) {     
            var event = Map.deque();         
            doAPICall(event.device, event.action, event.value);             
        } 
    } 
    

    【讨论】:

      【解决方案2】:

      首先,你应该只有一个数组来保存一个事件对象,否则你真的太复杂了。

      接下来只是循环事件,并查看添加新事件时是否已经存在相同的设备/操作之一。

      尝试这样做:

      var inCall = false;
      var queue = [];
      
      // add call to the queue, at the end
      function addAPICall(device, action, value){
        var found=false;
        for(var i=0, event; event = queue[i]; i++) {
          if(event.action == action && event.device == device) {
            event.value = value;
            found = true;
            break;
          }
        }
        if(!found) {
          queue.push({device: device, action: action, value: value});
        }
      }
      
      function doAPICall(device, action, value){    
          inCall = true;
          // call server here
          // if not successful, we should add this item to the queue again
          inCall = false;
      }
      
      function callAPIQueue(){
          if(!inCall && queueArrayDevices.length > 0){
          var event = queue.shift();
              doAPICall(event.device, event.action, event.value);        
          }
      }
      
      // start queue processing
      setInterval(callAPIQueue, 400)
      

      【讨论】:

      • 谢谢,马丁。这几乎就是我想要的。只需进行一项更改 - 应该从doAPICall 的队列中删除事件,而不是提前(我调用那里的服务器,因为我需要等待它的回复)。
      • 好吧,您可以将队列中的事件转移从 callAPIQueue 移动到 doAPICall,这应该可以满足您的要求。
      猜你喜欢
      • 2021-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-03
      • 2011-03-03
      相关资源
      最近更新 更多