We have an object that looks like this:

const foo = {
  expensiveOperator() {
    // I will spend a lot of time returning results
    this.cache = computeResult();
    return this.cache; }}Copy the code

If we need to call foo.expensiveOperator a lot in our business, and each call takes a lot of time. So at this point we’re thinking, can we temporarily cache this result? Today we are going to discuss a solution to this problem.

Most directly, we can define a ‘cache’ property on this object to store our results:

const foo = {
  cache: null.expensiveOperator() {
    if (this.cache) {
      return this.cache;
    }
    
    // I will spend a lot of time returning results
    this.cache = computeResult();
    return this.cache; }}Copy the code

Using this pattern, we can already avoid doing this expensive operation frequently.

Foo. Cache is a “private property” that can only be modified by foo.expensiveOperator. However, JS objects can not set private properties, so we need to use the Module Pattern design Pattern to encapsulate.

It’s actually quite simple, and you’ve probably seen this design pattern before. It was first promoted by Douglas Crockford and introduced in JavaScript Language Essentials (p. 40).

const foo = (function(){
  let cache = null;

  return {
    expensiveOperator() {
      if (cache) {
        return cache;
      }
      
      // I will spend a lot of time returning results
      cache = computeResult();
      returncache; }}}) ()Copy the code

The above could have been done with the Class notation, but personally, I’m nota big fan of the JS Class notation. I find it ugly and prefer the object Literal notation notation. Of course, I’m not saying Class is a bad way to write it, because it makes annoying stereotypes disappear 🙂

So let’s see if we can keep improving.

If we only write one, if we have a lot of operations in foo that need to be cached, then we have to define a variable for each operation to store the cached value, and then we have to add logic to determine whether the cache exists each time. I used this structure in my projects as well, and when the cache was too large, I clearly felt confused and unable to add more cache in the future.

Now let’s introduce a new mode to solve the above problems, which is also the best solution to solve this problem in my opinion.

First we define a get property and then write the value to the Object using the Object.defineProperty API after the first fetch. The code looks like this:

const foo = {
  get expensiveOperator() {
    // A time-consuming operation
    const actualData = computeResult();

    Object.defineProperty(this."expensiveOperator", {
        value: actualData,
        writable: false.configurable: false.enumerable: false
    });

    returnactualData; }}Copy the code

Using this structure, we don’t need temporary variables to store in the cache. We also make this property unmodifiable to prevent the stored value from being tampered with. You might think it’s a lot of code, but our defineProperty procedure can be encapsulated as a function, like the following:

const foo = {
  get expensiveOperator() {
    // A time-consuming operation
    const actualData = computeResult();

    defineProperty.call(this.'expensiveOperator', actualData); 

    returnactualData; }}function defineProperty(propertyName, value) {
  Object.defineProperty(this, propertyName, {
    value,
    writable: false.configurable: false.enumerable: false
  });
}
Copy the code

But I also found a disadvantage, that is, when the object exists, we want to modify the existence of expensiveOperator is not so convenient, we had to let the object re generated. But still, this method is brilliant.

The above case is suitable for the case where the cached property values do not change during the lifetime of the object, and for me, it is very suitable.

Caching is the simplest, crude and effective way to improve the performance of our software. However, in specific business scenarios, each scheme has its own advantages and disadvantages. Finally, it depends on the situation to discuss.