baconjs / bacon.js

Functional reactive programming library for TypeScript and JavaScript

Home Page:https://baconjs.github.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

RangeError: Maximum call stack size exceeded

sandzone opened this issue · comments

I am doing a spreadsheet calculation using Bacon.js. I get the Max call stack error for larger sheets.

There is no infinite recursive loop in the spreadsheet. But, it has a few cells which lead to updates in more than 2000 other cells.

Is there any limit on the number of buses and combinations one can do. My current spreadsheet has ~15000 buses.

Hmm... The required stack size should be propertionate to the depth of your spreadsheet dependency tree, not its width. It might very well be though that in the Bacon.js internals there are points where recursion is used when iteration would be more suitable.

So, what do you call stacks look like? Can you post me a stack trace? A codepen or fiddle to reproduce the problem would be super nice too!

Here's the stack trace.

screenshot 22

This is the main section of the code that causes the error. Hope it helps.

Object.keys(xl_cells).forEach((d,i)=>{      
        if (hasRange(xl_cells[d]))  {          
          //Each of the refs is an input bus to the current cell
          let input_ref_buses = getReferences(xl_cells[d]).map((cell_idx)=>{
            return this.output_reference_bus[cell_idx];
          });

          //Combine all these values by a logic to set a value on the current cell
          var results = Bacon.combineAsArray(input_ref_buses);
          results = results.map((args)=>{

          let index = 0;

           //return result based on the formula in that cell --- once all the arguments are live              
           let expr_with_values = xl_cells[d].replace(/[A-Z][A-Z0-9\-\s]+\![A-Z]+[0-9]+/ig, (match, x, string)=>args[index++])        

            return math.eval(expr_with_values).toFixed(3);
           });



          results.onValue((voila) => {
              this.values[d]=voila;
              if (counted_refs.has(d))  {
                this.output_reference_bus[d].push(voila);
            }
        })
      }
    })

Object.keys(xl_cells).forEach((d,i)=>{
        if (typeof xl_cells[d] !== 'string')    {
            this.values[d]= xl_cells[d];
            if (counted_refs.has(d))    {
                this.output_reference_bus[d].push(xl_cells[d]);
            }
        }
    })

Cannot get much info from the stack trace: it doesn't look like there's much going on in the stack. A dozen lines of stack shouldn't cause a stack overflow. I expected to see a repeating pattern involving the Bacon.js internals. Cannot help you with this info. If you can demonstrate that the stack overflow is caused by Bacon.js, I'll take a look that the details.

Thanks @raimohanska. I may have an idea of what is happening here. As a shortcut into checking if the issue is with bacon.js, I implemented my spreadsheet with RxJS.

It doesn't produce a similar error. But, it takes a ridiculous amount of time for its combineLatest operation. 2-3 minutes if I change some of the cells.

I realised that the combine methods --- which basically compute when any of the observables change --- are not optimal for spreadsheet calculations. Some of the cells are recalculating 20,000 times.

So, I tried using the zip method and sending all the constants whenever a value changes. It works faster. But, it is still slower than Excel or online spreadsheets. I haven't explored how those are implemented. But, I am trending towards the view that I need to use graphs to perform spreadsheet calculations.