While on a Google Apps Script Discord Server a great question came up as to what loop was faster when iterating over an array. If you are curious about Object loops please see this post. After some poking around the net we found lots of answers but every answer was specific to their platform or to a certain browser. So I thought it might be nice to do some testing for Google App Scripts. I am not sure if Google App Script IDE is affected by your browser or machine speed at all but thought it would be fun to post the results of my test.
Forwards
BIG shout out to Rahul’s Blog that give some really good ways to test each loop. I based my my code on their code and the only difference is I am not using a library to measure time and I am just using a Date constructor to do my timing. I have asked permission to re-run his tests and come to my own conclusions for GAS. So credit given where credit due. Thanks Rahul!
Pre Thoughts
A Date constructor is only accurate to the millisecond so it is not super accurate. To adjust for this I decided to run more tests to help get more accuracy.
Google App Scripts execution times can swing wildly swings because of many different factors and Google. IE I have scripts that take 60 seconds to run one time and 180 seconds the next time. So by running more tests I hope to help average out these issues.
All tests are all preformed one at a time and I have tried to choose a number of loops so that all the test can run inside of the 6 minute limit that Google gives for a GAP. I did some testing first to see what the longest loop code was first and then tried to find the most amount of loops I could do inside of a 5 minute window to ensure all the test were the same and as accurate as possible (the longer they run the more accurate I am hoping the average will be).
Setup
I created a new Google App Script project and added the following code to it
function test() {
var numbers = []
for (var i = 0; i < 1000000; i++){
numbers.push(i)
}
var d1 = new Date();
for (var iterationNumber = 0 ; iterationNumber < 1000; iterationNumber++){
// Place test code here to test
}
var d2 = new Date();
Logger.log(`On average it took ${(d2.getTime() - d1.getTime())/1000}ms`)
}
Explanation of Code
The first loop is to create an array of 1 million elements (0 – 999,999).
Captures the date.
We then run through a loop x1000 times and inside that loop we test our loop code.
Capture the date again.
We subtract the 2nd date in milliseconds from the 1st date in milliseconds to get how long it took in total and then divide that answer by the number of loops we did to get an average time in milliseconds.
The reason we go through the loop so many times to test the loop code is because most loops are so fast we don’t have an accurate way to measure the amount of time it takes to complete and have an accurate enough number to allow for comparison. By running the test more times and then averaging it we get a more accurate measurement that also takes into account slowdowns of the service.
Different Ways to Loop
Map() Method
numbers.map( num => num );
forEach() Method
numbers.forEach( num => num );
For…in Statement
for (num in numbers) {
num;
}
For…of Statement
for (num of numbers) {
num;
}
For Loop – Count Up
for (var num = 0; num < numbers.length; num++) {
numbers[num];
}
For Loop – Count Down
for (var num = numbers.length; num >= 0 ; num--) {
numbers[num];
}
For Loop – Count Up (length referenced)
const length = numbers.length;
for (var num = 0; num < length ; num++) {
numbers[num];
}
For Loop – Count Down (length referenced)
const length = numbers.length;
for (var num = length; num >= 0 ; num--) {
numbers[num];
}
While Loop – Count Up
var num = 0;
while (num < numbers.length) {
numbers[num];
num+=1;
}
While Loop – Count Down
var num = numbers.length;
while (num > 0) {
numbers[num];
num-=1;
}
While Loop – Count Up (length referenced)
const length = numbers.length;
var num = 0;
while (num < length) {
numbers[num];
num+=1;
}
Results
Loop Type | Milliseconds | ||
1st | for Loop – Count Up (length referenced) | 0.575 | |
2nd | while Loop – Count Up (length referenced) | 0.639 | |
3rd | for Loop – Count Up | 0.664 | |
4th | for Loop – Count Down | 0.748 | |
5th | for Loop – Count Down (length referenced) | 0.846 | |
6th | while Loop – Count Up | 0.877 | |
7th | while Loop – Count Down | 1.427 | |
8th | for…of Statement | 2.107 | |
9th | forEach Method | 23.537 | |
10th | Map Method | 39.050 | |
11th | For…in Statement | 287.585 |
Now that we know which ones by far are the slowest I am going to remove them so that we can test the fastest ones only to see if we get the same results. Let’s remove anything that is above 1 ms and really hammer these chunks of code by looping over them 350,000 times
Loop Type | Milliseconds | ||
1st | while Loop – Count Up (length referenced) | 0.564 | |
2nd | for Loop – Count Up (length referenced) | 0.642 | |
3rd | while Loop – Count Up | 0.629 | |
4th | for Loop – Count Up | 0.666 | |
5th | for Loop – Count Down | 0.845 | |
6th | for Loop – Count Down (length referenced) | 1.035 |
So looking at this we can infer a few things maybe more iterations are subject to more delays or server slow downs maybe this is a more accurate number. Who knows. A few changed place but relatively stayed the same. For giggles I decided to just do 10 loops as most people would not be hammering a loop this bad and it’s not realistic
Loop Type | Run 1 | Run 2 | Run 3 | |
for Loop – Count Up (length referenced) | 1.3 | 1.4 | 1.5 | |
while Loop – Count Up (length referenced) | 1.2 | 1.6 | 1.5 | |
for Loop – Count Up | 1.6 | 1.4 | 1.8 | |
for Loop – Count Down | 1.2 | 2.0 | 1.8 | |
for Loop – Count Down (length referenced) | 1.5 | 2.0 | 2.1 | |
while Loop – Count Up | 2.0 | 1.4 | 3.3 | |
while Loop – Count Down | 2.1 | 2.6 | 2.2 | |
for…of Statement | 13.6 | 11.6 | 9.9 | |
forEach Method | 19.2 | 21.2 | 18.6 | |
Map Method | 36.1 | 41.9 | 30.3 | |
For…in Statement | 276.8 | 343.5 | 296.3 |
Conclusion
Take it for what it is, just a bunch of silly tests but they still show some results that we can be assured of:
- a ‘for…in’ statement is horribly slow in GAS, don’t use them!
- A ‘for Loop’ seems to be the most efficient way in GAS to iterate over an array
Take my results as you will, Peace Out!