kubetail-org / sentineljs

Detect new DOM nodes using CSS selectors (650 bytes)
MIT License
1.13k stars 51 forks source link

Sentinel order not equal to DOM order #12

Closed petermonte closed 5 years ago

petermonte commented 5 years ago

Sentinel is loading elements in backwards order.

This is DOM

<div>div</div>
<span>span</span>
<strong>strong</strong>

This is JavaScript

sentinel.on('div', function(el) {
  console.log(el)
});

sentinel.on('span', function(el) {
  console.log(el)
});

sentinel.on('strong', function(el) {
  console.log(el)
});

This is the console log

<strong>strong</strong>
<div>div</div>
<span>span</span>

For a better example of this behavior please look at this demo on jsfiddle

amorey commented 5 years ago

I tested it out in Chrome and Firefox and didn't see this behavior but I was able to reproduce it in Safari. More specifically, I found that the execution order changes every time you reload the browser. Under the hood SentinelJS uses the animationstart event to detect new DOM elements so the callbacks execute in the same order as the browser event fires so I don't think there's a way to control the execution order. Does that create a problem for your application?

petermonte commented 5 years ago

@amorey thanks for the feedback.

In a way it does. On my side I got Chrome and Safari reproducing the behavior but Safari being unpredictable.

On the grandfather / father / sun logic I understand that the sequence should start from the top to bottom. But take a look at my example and you will see that under the hierarchy the sequence is correct but not with the side by side context.

When combining all libraries into one single js file I can determine the load sequence and therefore comply with the dependencies on each component. But now that became unreliable and so raises some concernes whether to continue or not with Sentinel.

One simple solution would be to parse existing nodes on page DOMContentLoaded and on each one of these events run Sentinel. So the logic would be: load the markup sequence as it is (for all browsers) and then prepare the page to deal with new markup built and appended to DOM on the FLY. Yet this raises another issue. If I call a function to initialise a component on DOMContentLoaded and then I implement the Sentinel listener I will have that same function called twice.

window.addEventListener('load', function() {
    // process element in a browser DOM load sequence
    // 1º this will call element belonging to DOM on load
    const myClass = document.querySelectorAll('.my-class');
    console.log(myClass);

    // now prepare script to process element on Sentinel sequence
    sentinel.on('.my-class', function(el) {
        // 2º this will also call previous element belonging to DOM on load
        console.log(el);
    });
});

output

▶︎ NodeList [div.my-class]
▶︎ <div class="my-class">...</div>
amorey commented 5 years ago

Parsing the DOM on DOMContentLoaded and then using SentinelJS for post-load DOM insertions sounds like a good solution. Let me know if you run into any other issues using SentinelJS.

petermonte commented 5 years ago

yup, but would be nice t find a way to not have a duplicate call with this logic.