在RxJs中使用背压进行击键

时间:2016-03-25 17:31:35

标签: javascript reactive-programming rxjs

我正在尝试使用RxJS捕获用户击键,并为每个笔划生成一个结果对象,其中包含,笔划的持续时间(时间)在keyupkeydown事件之间),以及之前笔划之间的区间(使用timeInterval)。 有关概述,请参见下图。

到目前为止,我的代码正在运行:Hello输出ShiftLeftHELLO

但是当我写更快(像往常一样)时,一切都会中断,World输出ShiftLeftShiftLeftOLD

您是否对我的代码中实现backpressure,缓冲或其他内容有任何建议以防止此行为?

(function (document) {
	var textarea = document.querySelector("#input");
  var keyUpStream = Rx.DOM.keyup(textarea);
  var keyDownStream = Rx.DOM.keydown(textarea);
  var keyStrokeStream = Rx.Observable.merge(keyDownStream, keyUpStream);

  var keystroke = keyStrokeStream.filter((function() {
    var keysPressed = {};
    return function(e) {
      var k = e.which;
      if (e.type == 'keyup') {
        delete keysPressed[k];
        return true;
      } else if (e.type == 'keydown') {
        if (keysPressed[k]) {
          return false;
        } else {
          keysPressed[k] = true;
          return true;
        }
      }
    };
  })())
  .distinctUntilChanged(function (e){
    return e.type + e.which;
  })
  .timeInterval()
  .bufferWithCount(2)
  .zip(function (evts){
    return {
      "ts" : Date.now(),
      "key":  evts[0].value.code,
      "evts" : evts,
      "duration" : evts.reduce(function(a, b){
        return b.value.timeStamp - a.value.timeStamp;
      })
    };
  }).subscribe(function (e){
    console.log(e);
    document.querySelector("#output").textContent += e.key.replace("Key", '');
    document.querySelector("#console").textContent += JSON.stringify(e);
  });
})(document);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.1.0/rx.all.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs-dom/7.0.3/rx.dom.js"></script>
<h1>KeyStroke</h1>
<textarea id="input" rows="5" cols="50"></textarea>
<div id="output"></div>
<div id="console"></div>

Streams

1 个答案:

答案 0 :(得分:0)

免责声明:Rxjs noob在这里。

问题是你的代码在从同一个密钥进行keydown之后需要来自密钥的密钥。当您快速键入时,您在击键时遇到竞争条件,从而产生具有多个键盘或键盘的缓冲区。不是你对缓冲区的期望。

我修改了代码以利用您的过滤功能。该函数仅返回keyup事件,并保存相应的keydown笔划。这样,您可以计算过滤函数中的间隔。我非常确定只使用RxJS函数是一个更优雅的解决方案,但由于你已经在过滤函数中使用了状态,我已经修改了一点。

该片段现在显示正确的输出。我认为它解决了你的问题,但它并不是一个使用RxJS的好方法(正如我所说的那样我们在过滤函数中存储状态)。

&#13;
&#13;
<div class="wrapper">
  <div class="child">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam tincidunt posuere velit, nec sodales augue viverra et. Cras vehicula in metus ac suscipit. Vivamus porta vestibulum nisl at volutpat. Pellentesque faucibus convallis elit, nec consectetur augue egestas sed. Pellentesque commodo viverra est sit amet dignissim. Nunc imperdiet condimentum tellus, in fermentum est consectetur a. Nunc quis nisi ac massa volutpat elementum et tincidunt quam.

Aenean sed mollis ante. Vivamus et lacus in dolor venenatis semper a ac tellus. Duis sed sollicitudin eros. Integer non volutpat ante, eu molestie lacus. Quisque eros enim, pharetra vitae vehicula a, pretium non metus. Vivamus at eleifend purus. Donec congue porta mattis. Mauris ac lobortis odio. Sed massa purus, blandit vitae massa ac, eleifend porta libero. Quisque magna elit, mollis sed pharetra quis, aliquam vel sem. Nulla tristique aliquet nunc, eget convallis eros feugiat vitae. Etiam posuere dolor at est scelerisque, nec rutrum lorem dignissim. Proin pharetra, massa eu volutpat pretium, dolor velit finibus augue, eget fermentum felis arcu varius dolor. Donec dapibus malesuada nunc et iaculis. Aliquam id ligula fermentum, tincidunt nisl a, molestie ex.

Vestibulum elementum sem id cursus pretium. Sed blandit urna ac ornare pellentesque. Fusce rutrum mauris nec lectus dapibus pulvinar. Donec id fringilla tellus, imperdiet eleifend sem. Morbi ultricies tempus neque ac sodales. Praesent pretium nisi vel justo tempus, eget ultrices orci commodo. Nunc placerat pellentesque condimentum. Duis sollicitudin elit nec neque suscipit, sed accumsan nisl facilisis. Morbi sem magna, aliquam at pretium nec, commodo nec ante. Donec dapibus vehicula felis, ac eleifend leo pharetra id. Vestibulum sagittis justo elit, luctus porta turpis commodo ut.
    </div>
  
  </div>
&#13;
	(function (document) {
	  var textarea = document.querySelector("#input");
	  var keyUpStream = Rx.DOM.keyup(textarea);
	  var keyDownStream = Rx.DOM.keydown(textarea);
	  var keyStrokeStream = Rx.Observable.merge(keyDownStream, keyUpStream);

	  
	  var keystroke = keyStrokeStream.filter((function() {
	    var keysPressed = {};

	    return function(e) {
	      var key = e.which;
	      var result;

	      if (e.type == 'keyup' && keysPressed.hasOwnProperty(key)) {
	        e.strokeInterval = Date.now() - keysPressed[key];
	        delete keysPressed[key];
	        return true;
	      } else if (e.type == 'keydown') {
	        if (!keysPressed.hasOwnProperty(key)) {
	          keysPressed[key] = Date.now();
	        }
	        return false;
	      }
	      return false;
	    };
	  })())
	  .map(function (evt){
	    return {
	      "ts" : Date.now(),
	      "key":  evt.code,
	      "duration" : evt.strokeInterval
	    };
	  })
	  .subscribe(function (e){
	    console.log(e);
	    document.querySelector("#output").textContent += e.key.replace("Key", '');
	    document.querySelector("#console").textContent += JSON.stringify(e);
	  });
	})(document);
&#13;
&#13;
&#13;