简体   繁体   中英

What is the difference between these 2 lines of code?

Background

Today the servers were on fire because the app was crashing. After checking the servers, I found out that the memory kept going up which caused PM2 to eventually kill and restart the process.

Code

This was caused because I made a fix. The original code was the following:

const cache = this.cache[script] = this.cache[script] || {};

After seeing that I thought: "Surely this is a typo, and the original creator meant something else, like this":

const cache = this.cache[script] || {};

Problem

By fixing that one line , the memory started growing and accumulating until filling the entire server.

I am blown away ... obviously I had to revert it back to the original version ...

Question

What is the difference between those two lines?

The first one writes {} to this.cache[script] if there is no property in this.cache with the name in the variable script (or there is but its value is falsy). The second doesn't.

So that means if you call this code more than once (or have it in more than one place), with the first code, all of them will end up sharing an object (stored on this.cache[script] ), but with the second code, they'll all create and use their own, new objects.

That's why you had memory ballooning, the code was never caching the objects and constantly creating new ones.

Example:

 class Example { constructor() { this.cache = Object.create(null); } getTheCache1(script) { const cache = this.cache[script] || {}; return cache; } getTheCache2(script) { const cache = this.cache[script] = this.cache[script] || {}; return cache; } } const e1 = new Example(); const e1c1 = e1.getTheCache1("foo"); const e1c2 = e1.getTheCache1("foo"); console.log("e1c1 === e1c2? " + (e1c1 === e1c2)); const e2 = new Example(); const e2c1 = e1.getTheCache2("foo"); const e2c2 = e1.getTheCache2("foo"); console.log("e2c1 === e2c2? " + (e2c1 === e2c2)); 

Or a simpler example:

 let a; // a starts out undefined console.log("const b = a || {};"); const b = a || {}; console.log("typeof a: " + typeof a); // "typeof a: undefined" console.log("typeof b: " + typeof b); // "typeof b: object" console.log("a === b? " + (a === b)); // "a === b? false" console.log("const c = a = a || {};"); const c = a = a || {}; console.log("typeof a: " + typeof a); // "typeof a: object" console.log("typeof c: " + typeof c); // "typeof c: object" console.log("a === c? " + (a === c)); // "a === c? true" 
 .as-console-wrapper { max-height: 100% !important; } 

All of this works because the result of an assignment is the value that was assigned. So here:

let a, b;
b = a = a || 42;

what happens is:

  1. the expression a || 42 a || 42 is evaluated, resulting in the value 42 since undefined || 42 undefined || 42 is 42 .
  2. the expression a = <value> is evaluated, where <value> is the result of Step 1. So 42 gets assigned to a . The result of that expression is the value that was assigned ( 42 ).
  3. the expression b = <value> is evaluated, where <value> is the result of Step 2. So 42 gets assigned to b .

But without the a = part of that:

let a, b;
b = a || 42;

it's just

  1. the expression a || 42 a || 42 is evaluated, resulting in the value 42 since undefined || 42 undefined || 42 is 42 .
  2. the expression b = <value> is evaluated, where <value> is the result of Step 1. So 42 gets assigned to b .

...leaving a unchanged.

Let us add some parenthesis:

const cache = (this.cache[script] = (this.cache[script] || {}));

This one line does two things:

  1. Initializes this.cache[script] if it is undefined
  2. Initializes cache variable with a reference to this.cache[script]

As a result, modifications to the cache variable are also reflected inside this.cache[script] .

The alternate code will either:

  1. Initialize cache variable with a reference to this.cache[script]
  2. Initialize cache variable with a reference to a blank object

Depending on the above, modifications to cache variable will or won't be reflected inside this.cache[script] .

I am guessing the portion of the code that broke relies on this.cache... being up-to-date but the code that uses cache variable updates... nothing.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM