/ Callback vs For Loop
DEMO | DOWNLOAD | DEPLOY | SEARCH
Login

Function Callbacks

When writing code in Jsi be aware that function callbacks are slower than for loops. For example, in:

x = [1,2,3], sum=0;
x.forEach(function(n) {sum+=n;});
for (var n of x) sum+=n;

the forEach function call is slower.

Speed Comparison

The following shows just how much slower:

var x = new Array(10000).fill(1);

function loop() {
   var sum=0;
   for (var n of x) sum+=n;
   return sum;
}

function func() {
   var sum=0;
   x.forEach(function(n) {sum+=n;});
   return sum;
}

function noop() {
   var sum=0;
   x.forEach(noOp);
   return sum;
}

;Util.times(loop);
;Util.times(func);
;Util.times(noop);

which outputs:

Util.times(loop) ==> 49892
Util.times(func) ==> 206804
Util.times(noop) ==> 144220

As can be seen, even noOp call is slower due to overhead from function call setup.

Case Study

Here is an example that considers the best way to implement a range function like:

function range(size, start, step) {
    var foo = [];
    for (var i = start; i <= size; i+=step)
       foo.push(i);
    return foo;
}
range(10,1,1);

Conventional JS

A quick look on Stackoverflow.com shows results for range and sequence. Note the mind-bending ways of trying to accomplish this seemingly simple task.

A popular answer was:

var N = 10; 
Array.apply(null, {length: N}).map(Number.call, Number)

Jsi Solution

Unfortunately the above doesn't work in Jsi and:

  • It needs a large EXPLANATION section, even though it is only 1 line!
  • Most other answers require ES6, which Jsi does not have.
  • Many correctly observed you are probably better off using a for loop.

Here are 2 implementations that work in both Jsi and ECMA:

cat > /tmp/range.jsi <<EOF
function range(n=20, start=0, step=1) {
    return Array(n).fill(0).map(function(v,i,o) { return start+i*step; });
}
function range1(n=20, start=0, step=1) {
   var a = Array(n).fill(0);
   for (var i in a)
      a[i] = start+i*step;
   return a;
}

;range();
;Util.times(range);

;range1();
;Util.times(range1);
EOF

jsish --U /tmp/range.jsi

Output:

range() ==> [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ]
Util.times(range) ==> 1136
range1() ==> [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ]
Util.times(range1) ==> 358

Both work, but the for loop is easier to read and 3-times faster.

Conclusion

Callbacks may seem more elegant, but they are just not very efficient in Jsi. And code ends up being harder to read.