Javascript 击倒观测值和性能

Javascript 击倒观测值和性能,javascript,knockout.js,typescript,Javascript,Knockout.js,Typescript,我和淘汰赛一起工作已经一年多了,但仍然有一个问题我无法解决。 这更多的是“语法糖”问题,而不是实际问题。简单代码是用TypeScript编写的,但是应该可以,即使您从未听说过它 让我解释一下 假设我们有一个可观察数组(MyArray),其中每个元素都有“值”可观察。我们想要创建一个计算的可观察对象,以得到所有的总和 显而易见的做法是: public SommeOne = ko.pureComputed((): number => { var res = 0; for (va

我和淘汰赛一起工作已经一年多了,但仍然有一个问题我无法解决。 这更多的是“语法糖”问题,而不是实际问题。简单代码是用TypeScript编写的,但是应该可以,即使您从未听说过它

让我解释一下

假设我们有一个可观察数组(MyArray),其中每个元素都有“值”可观察。我们想要创建一个计算的可观察对象,以得到所有的总和

显而易见的做法是:

public SommeOne = ko.pureComputed((): number => {
    var res = 0;
    for (var i = 0; i < this.MyArray().length; i++) {
        res += this.MyArray()[i].Value();
    }
    return res;
});
public SommeOne=ko.pureComputed(():number=>{
var-res=0;
对于(var i=0;i
但是在本例中,对this.MyArray()的调用在每次迭代中计算两次。和“价值”一次。对于小型阵列(少于1000个元素),这是可以的,但对于大型阵列,这将成为一个问题。到目前为止,我的解决方案是:

public SommeOne = ko.pureComputed((): number => {
    var res = 0;
    var array = this.MyArray();
    for (var i = 0; i < array.length; i++) {
        res += array[i].Value();
    }
    return res;
});
public SommeOne=ko.pureComputed(():number=>{
var-res=0;
var array=this.MyArray();
对于(var i=0;i
在这一点上,我们只对数组函数求值一次(仍然是对值求值一次,但这没关系,我们需要它),它工作得很好

最后一个问题是:

如何在不创建中间“数组”的情况下实现第二个解决方案


对于一个数组来说这很好,但是如果你需要在两个数组之间进行减法,或者做一些更复杂的事情,这很快就会失控

您几乎肯定是在浪费时间担心这些优化。调用
this.myArray()
没有进行任何重要的计算。直接从复制,调用可观察或可观察数组时执行的逻辑如下:

function observable() {
    if (arguments.length > 0) {
        // Write
        //[Omitted since not relevant here]
    }
    else {
        // Read
        ko.dependencyDetection.registerDependency(observable);
        return _latestValue;
    }
}
除了函数调用的开销和依赖项检测所做的少量工作之外(当您不是从计算机内部调用时,依赖项检测基本上可能只是一个
noop
函数);observable函数只返回一个对数组的引用,或是它此刻所持有的任何对象的引用,而对象引用的成本非常低

数组的长度根本不是一个因素。它不会“成为较大数组的问题”(至少敲除部分不会;算法的其余部分可能取决于您正在执行的操作),并且您对敲除已经缓存的值的缓存肯定不会成为主要的性能增益。(它可能也不会使它变得更糟,尽管我认为它是可读性的一个打击,因为它引入了新的变量)


与任何性能问题一样;标准免责声明适用:只有当您首先证明这是代码中需要优化的一个领域,然后证明这是一个重要的性能问题时,才应该关注这一点。如果这是你的情况,当然你可以做一些基准测试,看看缓存值是否能提高你的性能,但是根据你的措辞,这里似乎有一个更基本的误解。

你几乎肯定是在浪费时间担心这些优化。调用
this.myArray()
没有进行任何重要的计算。直接从复制,调用可观察或可观察数组时执行的逻辑如下:

function observable() {
    if (arguments.length > 0) {
        // Write
        //[Omitted since not relevant here]
    }
    else {
        // Read
        ko.dependencyDetection.registerDependency(observable);
        return _latestValue;
    }
}
除了函数调用的开销和依赖项检测所做的少量工作之外(当您不是从计算机内部调用时,依赖项检测基本上可能只是一个
noop
函数);observable函数只返回一个对数组的引用,或是它此刻所持有的任何对象的引用,而对象引用的成本非常低

数组的长度根本不是一个因素。它不会“成为较大数组的问题”(至少敲除部分不会;算法的其余部分可能取决于您正在执行的操作),并且您对敲除已经缓存的值的缓存肯定不会成为主要的性能增益。(它可能也不会使它变得更糟,尽管我认为它是可读性的一个打击,因为它引入了新的变量)


与任何性能问题一样;标准免责声明适用:只有当您首先证明这是代码中需要优化的一个领域,然后证明这是一个重要的性能问题时,才应该关注这一点。如果这是你的情况,当然你可以做一些基准测试,看看缓存值是否能提高你的性能,但根据你的措辞,这里似乎有一个更基本的误解。

你可以在:
this.MyArray().reduce((res,it)=>res+it.value(),0)
中尝试使用或等效函数。但是,请记住,性能优化并不总是直观的,而且本机
Array#reduce
可能成本高昂。在进行大量更改之前,先分析一下代码,看看慢点在哪里。嗯,我还没有听说过这个库。在我看来,这似乎是一条路要走。我对数组的调用将只计算一次。对于简单的情况,它将非常有效,但如果我需要两个或多个阵列之间的交叉或数据收集,它将失败。至于评测,我正在做,就在今天,将所有Date.parse切换到Date.parseExact,收益是巨大的(大量数据,很多东西)。您可以将此作为答案发布,这将是我的出发点。一旦您做出决定,您可以发布一个自我答案和一个jsPerf基准测试。提供的所有解决方案都是O(n),因此我选择最具可读性的。(在我看来,u.reduce)您可以在以下位置尝试使用或等效函数:
this.MyArray().reduce((res,it)=>res+it.Value(),0)