Monthly Archives: April 2020

Optimization Gotcha's for for/i and forEach

So I mentioned something on my interview with Alex of NativeScripting.com that he did with me. And someone asked about this in the comments, so I decided to create a blog article on this specific optimization tip.

I am going to code this to a browser rather than in NativeScript because well JS in a browser is just plain easier to show the memory issues because you can plop the code in to a new browser tab and step through the code instantly. 🙂

<html>
<body><div id="stacklayout"></div></body>
<script type="application/javascript">

// Pretend Color class to be similar to NativeScript
class Color {
    constructor(val) { this._color = val; }
    toString() { return this._color; }
}

const <strong><em>colors </em></strong>= ["#ff0000", "#00ff00", "#0000ff"];
for (let i=0;i&lt;<strong><em>colors</em></strong>.length;i++) {
    const labels=["Wow","Awesome","Interview", "Alex", "Created!"];
    for (let j=0;j&lt;labels.length;j++) {
        const clr = new Color(<strong><em>colors</em></strong>[i]);
        const txt = <strong><em>document</em></strong>.createElement("div");
        txt.innerText = labels[j];
        txt.style.backgroundColor = clr.toString();
        const parent = <strong><em>document</em></strong>.getElementById("stacklayout");
        parent.appendChild(txt);
    }
}
&lt;/script>
&lt;/html>

And you should see something like this:

We are repeating the labels for each of the primary colors...

Or you might be used to doing something like this instead:

&lt;html>
&lt;body>&lt;div id="stacklayout">&lt;/div>&lt;/body>
&lt;script type="application/javascript">

class Color {
  constructor(val) { this._color = val; }
  toString() { return this._color; }
}

["#ff0000", "#00ff00", "#0000ff"].forEach((clr) => {
  ["Wow","Awesome","Interview", "Alex", "Created!"].forEach((word) => {
     const txtColor = new Color(clr);
     const txt = <strong><em>document</em></strong>.createElement("div");
     txt.innerText = word;
     txt.style.backgroundColor = txtColor.toString();
     const parent = <strong><em>document</em></strong>.getElementById("stacklayout");
     parent.appendChild(txt);
  });
});

&lt;/script>
&lt;/html>

Both have several issues, however the second one can be vastly worse than the first one depending on how many iterations. So lets walk through the issues.

So the Color class is fine, we are using it to show creating objects... So just ignore it for now.

const <strong><em>colors </em></strong>= ["#ff0000", "#00ff00", "#0000ff"];
for (let i=0;i&lt;<strong><em>colors</em></strong>.length;i++) {

These lines are fine, we allocated colors, then looped through them. So far so good. Lets proceed, what about:

const labels=["Wow","Awesome","Interview", "Alex", "Created!"];

Well here is the first issue; Fortunately for us, the v8 JS engine actually pre-allocates the 5 different string "Wow" through "Created!" when it parses the JavaScript however, each loop through it does create a brand new Labels array and then links those strings into it. So in this case it is small overhead; however in the 3 loops that still is 2 more sets of allocations and all new GC enties that have to be cleaned up after the loop is completed. If you were to put this single line of code outside the loop; your code runs the same, but no less memory usage and less processing.

 const clr = new Color(<strong><em>colors</em></strong>[i]);

What about this line, well in this case all 15 times it creates a brand new Color object. You can easily make this only be ran 3 times just by moving it outside the inner for (j) loop into the for (i) loop. In this example the Color class is very light weight. But many classes you create inside loops will be very heavy with lots of allocations going on when you allocate the class. So pay attention, 3 allocations vs 15 allocations, all by putting the line in the wrong spot...

Continuing on, most the rest of the lines has to be inside the loop; but I tossed another item into the loop, that wasn't needed... This line is very easy to accidentally end up in the loop because you needed it at that point.

     const parent = <strong><em>document</em></strong>.getElementById("stacklayout");

Yep, this has to do an expensive lookup in the dom to find this element, it never changes. It also has to allocate it to that "parent" variable 15 times. If you dropped it before/outside of both loops, you would have a single lookup and allocation...

---

Finally lets look at the last example; it suffers from the same issues. However, this one I used a Array.forEach rather than the simple for (i) loop. Why do I say it can be worse then? Well in small numbers, the difference is actually pretty tiny. The extra amount of memory it uses over a for (i) loop is also reasonable. But in larger loops (especially loops inside of loops inside of loops); the difference can end up being exponentially larger.

Your creating and calling functions, and all those functions now has added scopes and the engine has to setup all the callstacks for each and every iteration, additional error checking and just plain running a lot more code behind the scenes. So what is a simple for (i) loop in the first example, now became 15 EXTRA functions calls with all the extra overhead of cpu and memory that entails. Again in small chunks they are perfectly fine, but if you are wanting performance, every ms and gc adds up and sometimes they can add up very quickly when dealing with the Array helper functions that use callbacks...

As a better way to phrase this; imagine you have a for (i) loop that takes 5ms and a forEach loop takes 25ms to finish. Both are still dang fast, hard to even benchmark. But now you embed it in another forEach that also by itself takes 25ms. 25ms * 25ms = 625ms. More than half of a second. But, if you were to switch this to a for (i) loop each of them is 5ms. So, 5ms * 5ms = 25ms. Both are exponentially larger, but 25ms vs 625ms and the difference starts becoming much clearer. Now add a third loop; 5ms*5ms*5ms = 125ms. 25ms*25ms*25ms=15,625ms (or > 15 seconds!) In small chunks the time and memory used from a forEach is minuscule. But depending on how many times it is called; it can add up very quickly to be a major difference.

Please note this goes for all the nice Array helper functions, .map, .reduce, .filter, etc. Everyone of them that uses a callback, has somewhere between 2 times and 50 times as much overhead as a simple for (i) loop. Remember, despite this overhead; these functions are extremely fast. So don't be afraid to use them, but be more wary of using them in deeply nested code that can easily be called in loops when the datasets they are working against are also large.

As many items that you can actually move outside of your loop, the better off you are. This Includes any expensive calculations! You might be able to do 99% of the expensive calculation outside of the loop; and then finish off the last part of the calculation inside the loop...

I hope this answers the question about loops and performance. Every loop is a golden opportunity to greatly enhance your app,

Oculus and their horrible support policy, a tale of woe!

I've had a lot of bad experiences with companies over the years; but this one takes the cake (The cake is a lie!) for me, in how not to treat a customer (let alone a developer in your ecosystem).

For those who don't know who I am, I have written somewhere around a 100 plugins both open source and many for different clients. Primarily for the cross platform framework NativeScript. So I have plugins from making Unity run and communicate with NativeScript to even making ColdFusion be able to drive an NativeScript app. On the Hardware side, everything from mobile printers, credit card readers and just a week or so ago the cool SocketMobile barcode scanner. All of them work great with NativeScript. So in a nutshell, I play with lots of hardware and software and write a lot of code in a lot of industries, including optimizing business practices...

As such I have a number of phones, one of them is the Samsung Galaxy, which supports the GearVR, so as such I have been a Oculus developer for multiple years. I've been working on a couple ideas; and even created a couple concept Unreal apps on my GearVR devices.

So as many of you might not be aware of getting a Oculus Quest is a an experience in frustration, they are sold out everywhere (unless you want to be scalped and pay twice as much).

So, I thought I scored last week. I read an article that Oculus finally had some stock again. Connected to their site; found that they were already out of stock on the 64 gig version, so decided because I have no idea when they will be in stock again, I'd spring for the larger more expensive version... So placed my order, had an order number, everything seemed to be great...

Then the pain begins....

Two days later around midnight, I get this message:

I'm like what the HELL, I've been waiting forever and they just CANCELLED my order, no contact, no nothing; just lets cancel it... (Serious question, Oculus, why don't you put in this message why it was cancelled, since the person cancelling it knows.)

Make it stop...

Ugh, of course, I went immediate to their site and guess what:

Yep, all sold out again.. Shoot, well maybe they can undo the cancellation; and we can figure out why they would cancel a order and fix whatever mistake was made. Clicked the support link and of course it brings you to the generic support site (Serious question, Why doesn't the email link put you on the proper url?). Spend a few minutes finding the right form to fill out and send them a question asking the simple easy question of "Can you tell me why my order XXX was cancelled?"

Lets apply the thumb screws...

The automated system sent and email response and stated, it could be up to two business days; but they did respond in one! Very late the next day I get a message from CS saying thanks for contacting us... But man my heart dropped.

  1. do not create any new orders (Not than I can, its out of stock already!)
  2. WE ARE UNABLE TO RE-INSTATE IT.

At this point, I realize, I am screwed, I can't reorder even if I wanted to; and that they won't re-instate the order. They officially jumped from well this experience so far just sucks, wasting my time... to Oculus customer service/order system really sucks. WHY THE HELL DO YOU CANCEL A ORDER, IF YOU CAN'T RE-INSTATE IT? Seriously bad customer interaction at this point... If their is a order issue, and you can't re-instate it, then suspend/pause the order and deal with the issue, don't just CANCEL the order leaving the customer with NO recourse...

Electric shock therapy is best...

And to top it off; lets see why the cancelled it (this message came the next day)

So basically:

- If I'm in the military and serving anywhere outside of the United States and decide to buy a US model, I can't...
- If I'm a expat living anywhere else in the world; apparently we can't either.
- If I'm uncertain where I'm going to be in the near future (like was in college, now at home), and decide that I want to make sure all my mail is handled and sent to where I am currently, no matter when this ships and arrives... I can't...
- Worried about spouse abuse and sending all mail through a third party to eliminate the ability for them to track me via my mail. I can't....

Really, Oculus! You f**kin cancelled my order because I ordered a SINGLE device, am a known developer in your developer program for several years and wanted to ship it to a place that can re-ship it to where I'm actually located right now. Your going to cancel the order, leaving me no recourse...

Maybe Bleach will work...

Then state I can order it this way from any of your support partners, seriously? You say we can't do this; but you can get around us, this way. Here's a link to make it much simpler!

Honestly, management needs to make some heads roll, that has to be the stupidest policy I've ever heard of...

But for those who typically use a Reshipper/concierge for your mail; you need to use a friend (which I would have done had I known that up front, now it is too late!)...