jerosoler / Drawflow

Simple flow library 🖥️🖱️
https://jerosoler.github.io/Drawflow/
MIT License
4.42k stars 714 forks source link

Load time with large numbers of nodes is excessive #825

Open andyjessop opened 4 months ago

andyjessop commented 4 months ago

When you have small numbers of nodes, the load time is snappy and the responsiveness is very good (better than, e.g. ReactFlow, which has VDOM overhead).

When you have large numbers of nodes, the responsiveness is still great, but only once it has loaded, which takes a lot of time.

As far as I can tell, this is because adding each node is forcing a reflow. For example, loading 1k nodes takes around 5 seconds on my machine, whereas with ReactFlow it is around 300ms.

I think that this lib can get MUCH faster by batching DOM reads and writes.

Is there any scope for this?

andyjessop commented 4 months ago

This might be fairly easy by just rendering into a fragment, and then only appending the fragment into the DOM once all the nodes are ready.

jerosoler commented 4 months ago

Hi @andyjessop

The problem is connections.

Adding nodes is fast. Calculation connections points is slow.

In this example: adding 3000 nodes is instantly.

Uncomment code comented and is very slow.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Document</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/jerosoler/Drawflow/dist/drawflow.min.css" />
  <script src="https://cdn.jsdelivr.net/gh/jerosoler/Drawflow/dist/drawflow.min.js"></script>
  <style>
    #drawflow {
      position: relative;
      width: 100%;
      height: 800px;
      border: 1px solid red;
    }
  </style>
</head>
<body>
  <div>
    <div id="drawflow"></div>
  </div>
  <script>
    var id = document.getElementById("drawflow");
    const editor = new Drawflow(id);

    editor.start();
    let lastId = 0;
    const nodes = [];
    for (let index = 0; index < 3000; index++) {
        const nodeId = editor.addNode('test1', 1, 1, Math.floor(Math.random() * 3000) + 1, Math.floor(Math.random() * 1600) + 1, 'test1', {}, '<div>Num:'+index+'</div>');
        /*    if(lastId !== 0) {
                editor.addConnection(nodeId, lastId, "output_1", "input_1");      
            }
        nodes.push(nodeId);
        lastId = nodeId; */
    }
  </script>
</body>
</html>

The problem is that we are going to search the DOM for the x and y position of each input and output. Which takes a lot of time.

Which is currently difficult to modify.

jerosoler commented 4 months ago

Here is a possible solution: