cferdinandi / reef

A lightweight library for creating reactive, state-based components and UI.

Home Page:https://reefjs.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Regression in 10.0 with browser going 100% CPU and Reef's "get" function taking most time

GregOriol opened this issue · comments

I have a quite complex code with Reef that works well with versions 9.0.1 and below (worked well on 8.x), but after updating to 10.0, browsers just hang at 100% CPU and the page is frozen. I can't even open developer tools in Chrome and make a performance recording, while Safari's tools show this:

(the *-bundle are my code)

I don't know exactly which part of my code may trigger this because it's really a complex/big template. I'll try to isolate things.
Did anything change in Reef between 9 and 10 that can produce this issue?

Reduced test case please.

Working on it, trying to identify which part is getting reef crazy, not clear yet template and data are quite complex

Ok, got it: it's a sort called on a key/value array in the data that causes the problem.

Example:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>Test1</title>
</head>
<body>
    <div id="test1"></div>

    <script src="https://cdn.jsdelivr.net/npm/reefjs@10/dist/reef.min.js"></script>
    <script type="text/javascript">
        Reef.debug(true);

        let elem = document.querySelector('#test1');
        let app = new Reef(elem, {
            data: {
                test1: [
                    {
                        key: 'item1',
                    },
                    {
                        key: 'item3',
                    },
                    {
                        key: 'item2',
                    }
                ]
            },
            template: function (data) {
                return `
                <div>
                    ${data.test1.sort().map((c) => { return c.key; }).join(',')}
                </div>
                `;
            }
        });
        app.render();
    </script>
</body>
</html>

If you run it, you'll have 100% CPU usage and a frozen tab (tested in Safari 15, Chrome 96, Firefox 94).
But if you either remove .sort() or change Reef to 9, it works!
If the key/value array is replaced by a value only array like ['item1', 'item3', 'item2'], there is no problem.

The .map and .join are only for display purposes, they don't impact this behavior and can be removed to simplify further the example. The sort here doesn't actually sort the key/value array, my real sort uses a callback function on the objects but I removed it here for a simpler example.

Ahhhh yes, that helps!

So, in previous versions, the props object was an immutable copy of your data. Transforming it didn't trigger a UI updates.

For performance reasons, I decided to pass the data in raw in version 10 (which is what bigger libraries like React do). The general best practice with state-based UI's in "don't transform data in the template."

What's happening with you: sorting the data causes a render, which sorts the data, which causes a render, which... infinite loop.

I can fix that reverting to "immutable copy" for the props object.

As a temporary workaround, you can use the Reef.clone() method to create an immutable copy of the data before mutating it. I've got this flagged as a bug and will implement a fix when I get a moment.

let app = new Reef(elem, {
    data: {
        test1: [
            {
                key: 'item1',
            },
            {
                key: 'item3',
            },
            {
                key: 'item2',
            }
        ]
    },
    template: function (props) {
        let data = Reef.clone(props);
        return `
        <div>
            ${data.test1.sort().map((c) => { return c.key; }).join(',')}
        </div>
        `;
    }
});

Patched in 10.0.1. You no longer need to copy your data manually in the template. It includes a non-reactive copy

Not sure exactly what is going on yet, but with 10.0.1, I get the following error in the console with my current templates (but not the test one above):

Capture d’écran 2021-12-18 à 14 38 01

Capture d’écran 2021-12-18 à 14 30 35

Edit: ok, so this happens when a value in data is null, like:

    data: {
        test2: null
    },

Ah yea, overly broad type checking when creating a proxy. This should be addressed with v11.0.1, which is a major version bump.

If you can make the update, here's what's changed.

v11.0.1 looks good, all the problems above seem to be solved