当前位置:  开发笔记 > 编程语言 > 正文

纯javascript中的延迟分配

如何解决《纯javascript中的延迟分配》经验,为你挑选了3个好方法。

在这个问题中,我遇到了以下简化问题:

我们从一个带有value属性的Objects数组开始.我们想要为每个值计算它的总和的百分比,并将其作为属性添加到结构中.要做到这一点,我们需要知道值的总和,但这个总和不是事先计算的.

//Original data structure
[
  { "value" : 123456 },
  { "value" : 12146  }
]

//Becomes
[
  { 
    "value" : 123456,
    "perc"  : 0.9104
  },
  {
    "value" : 12146 ,
    "perc"  : 0.0896
  }
]

一个简单且可能最具可读性的解决方案是两次遍历数据结构.首先我们计算总和,然后计算百分比并将其添加到数据结构中.

var i;
var sum = 0;
for( i = 0; i < data.length; i++ ) {
  sum += data[i].value;
}
for( i = 0; i < data.length; i++ ) {
  data[i].perc = data[i].value / sum;
}

我们是否可以只通过数据结构一次,并以某种方式告诉只有在知道整个总和后才能评估百分比表达式?

我主要对解决纯javascript问题的答案感兴趣.那就是:没有任何库.



1> Nina Scholz..:

具有自修改代码的解决方案.

它将f计算功能移动到迭代结束,然后通过链接函数分配单个项目的百分比.

var data = [
        { "value": 123456 },
        { "value": 12146 },
    ];

data.reduceRight(function (f, a, i) { // reduceRight, i=0 is at the end of reduce required
    var t = f;                        // temporary save previous value or function
    f = function (s) {                // get a new function with sum as parameter
        a.perc = a.value / s;         // do the needed calc with sum at the end of reduce
        t && t(s);                    // test & call the old func with sum as parameter
    };
    f.s = (t.s || 0) + a.value;       // add value to sum and save sum in a property of f
    i || f(f.s);                      // at the last iteration call f with sum as parameter
    return f;                         // return the function
}, 0);                                // start w/ a value w/ a prop (undef/null don't work)

document.write('
' + JSON.stringify(data, 0, 4) + '
');


2> 小智..:

此解决方案使用单个循环来计算总和,并perc使用以下内容在每个元素上放置计算属性getter:

function add_percentage(arr) {
  var sum = 0;
  arr.forEach(e => {
    sum += e.value;
    Object.defineProperty(e, "perc", {
       get: function() { return this.value / sum; }
    });
  });
}

一个直截了当的推迟就是

function add_percentage(arr) {
  var sum = 0;
  arr.forEach(e => {
    sum += e.value;
    setTimeout(() => e.perc = e.value / sum);
  });
}

但是,这样做到底有什么意义呢?



3> Patrick Evan..:

例如,用一个较少的循环来实现这一点的方法是写出由所有可能的项组成的整个sum语句

var sum = (data[0] ? data[0].value : 0) +
          (data[1] ? data[1].value : 0) +
          (data[2] ? data[2].value : 0) +
          ...
          (data[50] ? data[50].value : 0);

for( i = 0; i < data.length; i++ ) {
   data[i].perc = data[i].value / sum;
}

并非这实际上是一个真正的解决方案

您可以使用Array的reduce函数,但它仍然是后台循环,并且每个数组元素都有一个函数调用:

var sum = data.reduce(function(output,item){
   return output+item.value;
},0);
for( i = 0; i < data.length; i++ ) {
  data[i].perc = data[i].value / sum;
}

你可以使用ES6 Promise,但是你还在添加一堆函数调用

var data = [
  { "value" : 123456 },
  { "value" : 12146  }
]
var sum = 0;
var rej = null;
var res = null;
var def = new Promise(function(resolve,reject){
    rej = reject;
    res = resolve;
});
function perc(total){
    this.perc = this.value/total;
}

for( i = 0; i < data.length; i++ ) {
  def.then(perc.bind(data[i]));
  sum+=data[i].value;      
}
res(sum);

Perf测试

加成声明
10,834,196
±0.44%
最快

减少
3,552,539
±1.95%减少
67%

承诺
26,325
±8.14
%慢100%

对于循环
9,640,800
±0.45
%慢11%


我不认为展开循环计数作为解决方案.
那个承诺的事情有点整洁,只是不必要的异步.`.perc`只能异步使用,并且应该是一个promise本身.顺便说一下,请不要调用promise变量`def`,并避免使用`rej`和`res`变量 - 只需将负责解析promise*的代码放在`Promise`构造函数回调中.
推荐阅读
360691894_8a5c48
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有