angular.js icon indicating copy to clipboard operation
angular.js copied to clipboard

Less memory use feature: add watchHash to ngModelOptions

Open litera opened this issue 10 years ago • 2 comments

Watchers check watched expression value differences and for this to work they save previous value. The problem is that this can have a major impact on resources as sometimes our model values are pretty large (i.e. users editing HTML content or textareas where users enter large amounts of text).

As these watched model values may be large it would be great if Angular had an additional ngModelOption called watchHash that would rather calculate hash of the model value and compare that. This hash calculation can be extremely simple to aid performance.

Here's a JSPerf example of various checksum/hash algorithms comparison.

The simplest checksum calculation can simply do the

checksum += value.charCodeAt(i) * (i + 1);

where resulting calculated value becomes larger with longer inputs. This may not be desired and we'd like to have a more evenly distributed value calculation (more like a real hash/checksum). Hence I'm currently using following watch string input calculation that's also quite fast. not as fast as simple summation, but still pretty fast.

function checksum(value) {
    // prime and factor used to ensure larger input does not imply larger checksum
    var prime = 0x56ca7561;
    var factor = 0x0123456b;

    // return 0 if string is empty or null
    if (!value) return 0;

    for (var i = 0, l = value.length, result = factor; i < l; i++)
    {
        result += value.charCodeAt(i) * factor;
        result &= 0x7FFFFFFF; // convert to 32-bit positive integer
        result ^= prime;
    }

    return result;
}

So whenever we'd know that our model value will be large, we can add this model option to instruct Angular to calculate hashes instead comparing whole values in watcher.

<textarea ng-model="someValue" ng-model-options="{ watchHash: true }" />

Default could also depend on bind type we're doing in our code:

  • if we're using ng-bind or interpolation then default watchHash would be false
  • if we're using ng-bind-html default would be true

litera avatar Feb 25 '15 09:02 litera

Not caching the oldValue however means that you cannot access it in the watchAction fn. This might be an acceptable tradeoff if you want performance, but it's definitely a bit confusing. That said, I think custom copy / compare functions might be the way to implement such a feature: 10096

Narretz avatar Oct 12 '15 20:10 Narretz

That's true, but when you need this kind of functionality I suppose one's aware of it. I arguably also suspect that new value is mainly used so this shouldn't be a problem.

litera avatar Oct 13 '15 11:10 litera