如何修改算法以减少延迟?

时间:2014-10-15 12:32:37

标签: javascript html algorithm dynamic

我有很多这样的输入,用户输入值:

<INPUT TYPE=TEXT NAME="Milk" ONKEYUP="convcase(document.convert.Milk.value)">
<INPUT TYPE=TEXT NAME="Buckwheat" ONKEYUP="convcase(document.convert.Buckwheat.value)">

和很多像这样的计算:

document.convert.Fe.value = BuckwheatFe * document.convert.Buckwheat.value + PeaFe * document.convert.Pea.value + MilkFe * document.convert.Milk.value + ...
document.convert.Hexadecanoic.value = BuckwheatHexadecanoic * document.convert.Buckwheat.value + PeaHexadecanoic * document.convert.Pea.value + MilkHexadecanoic * document.convert.Milk.value + ...

因此计算后的结果是动态显示的,当程序有数百种产品时,输入和计数之间的延迟太大。我计算所有产品:牛奶,荞麦......即使用户没有输入它们的价值。

你能告诉我如何修改算法以减少延迟吗?

3 个答案:

答案 0 :(得分:1)

我会接近以下内容。需要在计算中使用的输入可以用类表示,例如&#34; itemValue&#34;,然后检索一次然后缓存。这假设他们不会改变。

标记可能如下所示:

<form name="convert">
  Milk: <input class="itemValue" name="Milk" onkeyup="convcase(this)"><br>
  Buckwheat: <input class="itemValue" name="Buckwheat" onkeyup="convcase(this)"><br>
  Fe value: <input name="Fe"><br>
  Hex value: <input name="Hexadecanoic"><br>
</form>

Fe和Hexadecanoic值之类的东西也可以缓存。如果将节点集合转换为数组以便可以使用内置数组函数,它也会有所帮助。这些可能比使用for循环慢,所以如果它们是,则将 reduce 调用转换为循环。

// Helper to convert a NodeList to an array so built-in methods can be used
function toArray(list) {
  var i = list.length, arr = [];
  while (i--) {
    arr[i] = list[i];
  }
  return arr;
}

执行实际工作的功能:

var convcase = (function() {

  // Cache stuff in a closure. Note that the names of each factor set
  // must match the form control name where the related total is written
  var factors = {
       Fe: {Buckwheat:0.5, Milk:0.75},
       Hexadecanoic: {Buckwheat:0.6, Milk:0.82}
      };
  var nodes;

  return function (el) {

    // Only get nodes the first time, assumes they don't change, and convert to Array
    // This can be done before validation as it's not dependent on it
    nodes = nodes || toArray(el.form.querySelectorAll('input.itemValue'));

    // Validate el.value here and deal with invalid values.
    // Only proceed if it's a valid value

    // For each set of factors, do all the calculations and write totals to form
    for (var factor in factors) {

      // Get the factor set
      var set = factors[factor];

      // Write the total to the related form control
      el.form[factor].value = nodes.reduce(function(sum, node){
                                         sum += node.value * set[node.name];
                                         return sum;
                                       }, 0);
    }
  };
}());

我不会在keyup上执行此操作,我等待更改或模糊事件,因此只有在用户很有可能暂时完成计算时才会进行计算,否则可能会有很多无用的计算。

答案 1 :(得分:0)

将元素存储在数组中并使用循环。您还可以存储先前的值(旧的一个在其他数组中),并在执行计算之前将旧值与新值进行比较。如果值已更改,则只执行此操作。

答案 2 :(得分:0)

我知道一种处理此问题的标准方法。关键是:您不希望每个按键都触发算法。你想等待客户端停止输入(暂时);然后你触发算法。

(编辑:顺便说一下,请阅读下面的评论。你可能只是通过更改&#34; onkeyup&#34; by&#34; onchange&#34;)来帮助你。

使用clearTimeout / setTimeout组合,您可以做到这一点。我设定了打字时间&#39;到400毫秒,随意改变这个值。

<script>
var timer = null;
var interval = 400;  // feel free to change this value

function imputChanged(elm) {
  // if any previous key stroke happend less than 400ms ago; clearTimeout will cancel that request.
  // only the last request will trigger executeAlgorithm().
  clearTimeout(timer);  
  timer = setTimeout(function() {
      executeAlgorithm(elm);
    },
    interval
  );
}
function executeAlgorithm(elm) {
  // do what ever you have to do here. As an example, I show the value in a div
  document.getElementById('messages').innerHTML = elm.value;
}
</script>
<input onkeyup="imputChanged(this)">
<div id="messages"></div>

(编辑:看起来onkeyup在IE上的效果比onimput好;我现在将触发器设置为onkeyup)