Search posts, tags, users, and pages
What is the problem with the DOM? One of the most reasonable thing's I've heard is that the DOM does have side-effects. That's not really relevant outside of a functional approach but react insist on being functional so
A to A' obviously seams important the idea was to have no sideffects and a predictable mutation pattern. There is ofc some BS involved but luckily most devs are "users".
So in most cases I personally would stay declarative (HTML) with minimalistic CSS. because I don't need a rocket engine behind everything.
But as soon as my layout uses non synchronous update cycles so for example I have a component in the layout that should update on a dropdown change. The app-state to render-state issue is slowly starting to arise.
This is where react for example could come handy. I personally think it's still to bloated for such a simple task but the reasoning is more sensible. As soon as the page is not contained into 1 single Request and Response people tend to get confused.
The question of when a framework makes sense is like everywhere 1st usecase. It's always the question what we're trading. Do we need to know all cycles of updates? do we need to understand how an event really bubbles?
In my opinion based on my observations a lot of the modern JS-devs are framework users, they have to deliver and deliver and deliver so they try to push the thinking to their tools. that's what Gabor for example said "focus on the business-logic".
In my opinion, if you don't have a page that needs to be highly interactive .... you have to be an unexperienced programmer or you have way to much time, to add anything complex to your frontend as a complete framework.
But as soon as interactive asynchronous state changes / reactive state changes are necessary you probably have to much time or you are a classic old dog to not at least consider using a modern frontend solution for that.
I hope I am not to much off topic with my answer :)
Could you elaborate on these "side effects" as I've never heard of nor encountered any in some decade and a half of using them... in that way your second through fourth sentences just read as gibberish to me. I literally am not grasping what it is you are even saying there, though I suspect it's the type of scripted stuff I would NEVER allow on a website in the first place for all the reasons I've previously stated.
Since as soon as you do things like "reactive state changes" you're implementing scripted crap that is a instant WCAG violation unless you have scripting off fallback functionality already in place and are coding it as an enhancement... or delivering stuff that is not core content such as social discussions/plugins.
Even then I don't understand how Element.appendchild or Element.insertBefore would be any worse or cause problems that the outdated outmoded half-assed innerHTML += doesn't. Quite the opposite in fact!
But to be fair to me using innerHTML is as outdated an approach to adding content to a existing document as document.write. Weren't we being told fifteen years ago to STOP doing that?!? What happened to that?!? Is this the same thing as how HTML 5 pissed on the intent and improvements of 4 Strict with the halfwitted half-baked header/footer/main/article/section/nav/aside/audio/video/embed/hgroup tags and aria role nonsense, flipping the bird at accessibility and simpler code in the name of accessibility and simpler code?
If so, I'm with the Boy Wonder on this one, I'm officially whelmed.
-- edit -- and don't worry about being ALLEGEDLY off-topic with me. A conversation goes where it goes, and I have literally ZERO tolerance for the typical TLDR mouth-breathers who get their panties in a knot screaming "Off topic, OFF TOPIC" every time someone tries to use a simile.
... and no, before one of the real derps out there chimes in I did not just misspell smilie.
A function is said to have "side effects" if invoking that function multiple times with identical inputs does not produce the same output. A function that does produce identical output with a given set of inputs is known as a pure function. Programming with pure functions is a central tenet in functional programming and in frameworks like Redux and React as it produces predictable state, is fair easier to debug and trace, and eliminates a whole class of errors that exist when working with non-pure functions.
Matt Strom so basically side-effects are mutation of the global state. which would mean the state would be (mutated) A instead of (new) A' as it would be notated in math / functional. Also for example reading files or accessing the database are considered side-effects. Thanks for clearing up my non contextualized mumbelings :D I was lost in several thought the problems of a chaotic mind. ;)
About the WCAG which are very important we need to contextualize them as well. Because often people think in apps not pages .
That is one point I 100% agree with you ... those violations piss me off. I want to access a page regardless if there is javascript or not. That's why really good web-developers use progressive enhancements and just add the javascript on top as sugar for the UX.
But there is the new form of development which is app focused and that's where the whole WCAG is not relevant anymore but the 100ms response time as soon as the app is up. Also in certain business cases no one care if the SEO parser works they want an interactive graph search that spits out the correct results that partial works offline.
It seams to me that most of the time people confuse a website that is accessed with browser and should use WCAG a request response model and mainly synchronous behaviour with a web-app which is like a phone app containing a local state.
That's to me is the main difference and than there is the question of emphasis.
And based on those and more points I think we could take a more rational stance. Very often it's Hype driven development so people build a blog with react which to me is just stupid or bored and than other people jump onto it and soon we have an eccosystem of BS libs that just do one thing ....
request -> response -> render html
do I make sense ? or am I still besides the point? I didn't want to go into the dom manipulations because I am a low level guy so I definitly agree to some point. I wanted to stay on the overall-side
No offense guys, but what in the blue blazes does that have to do with ANY of it? Could you provide a real world example of where innerHTML+= does something so horribly different from createElement and createTextNode? OR where innerHTML= is different from doing a node flush followed by the same?
In case you don't know what a node flush is:
while (e.firstChild) e.removeChild(e.firstChild);
Again this is another case of you using words and terminology that I know, but that just doesn't mean ANYTHING to me and/or doesn't feel relevant to the context. It doesn't correspond at ALL to what is going on at the browser, DOM, or scripting level. Not one bit.
HOW is it producing anything different to violate that "pure function" hoodoo voodoo? (which to be honest is another of the reasons I think React is halfwitted rubbish, PARTICULARLY if you use it for CSR).
WHAT 'predictable state' isn't generated by doing:
function addDiv(target, text) {
var div = target.appendChild(d.createElement('div'));
div.className = 'added';
div.appendChild(d.createTextNode(text));
});
instead of:
function addDiv(target, text) {
target.innerHTML += '<div class="added">' + text + '</div>';
}
Other than the fact that the former is XSS injection-proof? Or that if I wanted to do more in the function I have access to the newly created element -- meaning that I have IMMEDIATE access to it instead of having to stop the current script execution long enough for the parser to de-parse the ENTIRE DOM, insert the new code, then re-parse into an all new DOM re-applying ALL the CSS rules?
How is doing this:
function allLI(ul, callback) {
var li = ul.firstElementChild;
while (li) {
callback(li);
li = li.nextElementSibling;
}
}
doing anything screwball that's different from this?
function allCells(ul, callback) {
var allLi = ul.getElementsByTagName('li');
for (var i = 0, li; li = allLi[i]; i++) {
callback(li);
}
}
Well, other than the fact the former won't screw up if you put another list inside the one we pass as 'ul', and runs 50-200% faster depending on browser engine? The only real problem with the former is it might try to process elementNodes that aren't LI, but then you've got WAY bigger problems like invalid markup!
Which of course is far, FAR less likely of a problem to show up if you're bothering to use the DOM instead of slopping HTML together in JavaScript strings since you NEVER have to worry about "did I close that tag properly?"
Or are you actually saying that the IMMEDIATE change to the live DOM when you do an appendChild / insertBefore is the problem? Hence the reference to mutated (chanced) vs. non (unchanged). That would be VERY unusual since having the stuff I just created NOT being available immediately is one of the entire reasons I had thought ten to fifteen years ago we were being told to STOP using innerHTML! That innerHTML's changes do not occur on the DOM until after the script execution ends is something I'm used to being a problem, not a desired outcome! If you can't handle the fact you just made a change YOURSELF to the DOM, there's something REALLY jacked up with your methodology or planning! The only way that would be an issue is if you somehow magically get multithreaded -- but then all you'd be doing is creating race conditions, which are a problem either way! At least having that a change was done actually existing on the DOM might give you something to look at and say "hey, something was done!"
I'm trying to wrap my head around when/where in a real world usage scenario these differences would cause problems... and I see none. Admittedly, when it comes to mind-numbingly asshat garbage like React, I see what it does, how it does things, and the coding methodology it advocates AS part of the problem!
I really don't get how people would use those by choice in building a website -- some stupid full stack crapplet or server-side code sure... but not on a website. Even if building a full stack crapplet I still wouldn't be screwing around with innerHTML or building nodeLists when I can avoid it. (mind you, there are legitimate cases for building nodeLists, but it shouldn't be the "rawrz eyes muss yuus tis" for every situation -- part of what pisses me off with jQuery)
Jason Knight, why do you keep going back to the whole "innerHTML += ..." argument. That's a straw man argument you're using to attack frameworks, which is completely irrelevant to frameworks.
Furthermore, you keep also going back to the whole WCAG thing, when using a framework in no way precludes accessibility.
Your arguments mainly seem to boil down to disdain for developers not doing a complete and thorough job, but instead of attacking that issue, you're attacking frameworks using contrived straw man arguments derived from very specific prior experiences of yours and then rashly generalizing those experiences. Furthermore, you're being extraordinarily obstinate with regard to learning concepts that the field of web development is comfortable with using. It's like you traveled to Russia and you're scolding people for speaking Russian.
well okay,
so the main difference is behavioural and that you can modify the direct api more easily.
and if I remember correctly this:
developer.mozilla.org/en-US/docs/Web/API/Document…
is actually one way to do it with actually no side effects to the DOM.
react does something like that the VirtualDom could be seen just a huge JS-Object and has an DOMElement as reference.
it diff merges the old virtual-dom state with the new virtual-dom state and only applies the difference and those get passed to the DOM in the end.
concurrency is not that big of an issue if you think functional and split the lists accordingly since you never mutate the global state you just have to build your structures accordingly so you can access them as you need.
is that a better answer?
j No actually that's not clarifying it at all... again I see words that just don't add up to a meaning to me, since nowhere are you saying what ALLEGED "side effects" on the DOM are happening or where/how that such a thing would even be relevant. I really have to question if you folks understand what I'm asking as your answers seem to be completely unrelated.
Modify WHAT "direct API" directly... what does some API even have to do with the subject unless the API itself is in fact rubbish by introducing problems that shouldn't even exist in the first place? ... and if it IS some API or framework or what-have-you causing these problems, why the hell would anyone be using them in the first place apart from a complete ignorance of how to use JavaScript in a client-side environment?
... and all instances of the DOM are huge JavaScript objects, that's kind of the point. Is that the point people are missing when they start throwing the words "virtual" in there when that's a nonsensical distinction? Just because you made your own instance or fragment separate from a live one doesn't make it "virtual" or any other such nonsense!
Much less what on earth does 'diff' have to do with it unless you're futzing around with markup, or making massive copies of nothing instead of just using the existing document correctly?
Though if you are talking concepts specific to systems like React, remember that my experience with react boils down to two things. 1) learning just enough of it to go "screw this incompetent nonsensical noise" and 2) having spent time with half my clients over the past three years ripping garbage like that OUT because of the general incompetence and ignorance of the people who put them in place!
Likewise the buzzwords "concurrency" and "functional" in practice -- for me at least -- mean NOTHING apart from trying to shoehorn fixed concepts into fitting every problem, instead of using the best tool at hand for the job. SOUNDS much like derpitude of trying to shoe-horn event driven language concepts like MVC into linear execution user called languages like PHP. That it can be done at all is more a testament to persistence and determination than it is rational thought.
... and again I'm just not seeing a real world case nor have I encountered a programming situation where what you are saying has ANY meaning, apart from the type of theoretical garbage. The type I've spent the past twenty years ripping out of programs and websites screwed over by stuff best left on whitepapers in academia.
Like React in its entirety. How to take the simplest thing -- creating markup from data and interacting with it both via user and server responses -- and making it as agonizingly, painfully, and needlessly difficult as possible!
Maybe I'm just getting too old for this ****...
CODE might help, an example of WHERE it is breaking might help... like an actual example, not second-rate legalese, propaganda buzzwords, and feel-good nomenclature.
Joe Gaspar you asked:
why do you keep going back to the whole "innerHTML += ..." argument
Because that's basically MY ENTIRE QUESTION IN THE FIRST PLACE? Gah, we are speaking English here right? Or is this like the joke about how in the pen and paper RPG traveller two people from the same village speaking the same language have a 50% chance of completely misunderstanding each-other?
The question I was asking in the first bloody place was why are people NOT using the DOM -- what's the alternative to using the DOM in terms of nodewalking and the various document.createxxx functions? innerHTML, innerText/textContent, and building nodeLists with the various getElementsBy/queryAll approaches. HENCE my showing code comparisons and asking why given the advantages of the DOM approach why people still crap into sites using innerHTML style methodology -- like via jQuery's .html(), or when react is used client-side for generation via string processing, or sending full markup client-side from the server via AJAX -- instead of a more sound and far less risky approach?
That was the entire blasted question this entire thread is ABOUT!!! Sheesh... Whiskey tango foxtrot...
As to ragging on the frameworks, it's because they seem to encourage NOT using the DOM, and I wanted to know WHY... Which is why I keep asking for why and instead just get second rate academia double-talk reeking of glittering generalities, card stacking, all mated to a defense of frameworks rooted more in bandwagon than actual fact!
With nobody seeming to actually even be understanding the question much less providing an actual answer...
I see since I don't want to waste time are some quick implementations
The first one is an react like meta abstraction in a simple implementation this is easy to read an understand. This has only side effect when it cleans the DOM and inserts the next fragment. since the Fragments and the DOM are not a reference but a COPY there is no side-effect for the next step -> modification of the fragment does not change the DOM directly. only the update function triggers this sideeffect.
With unwanted side effects: (createElement not createDocumentFragment)
<script>
'use strict';
// that is a meta DOM
// JSX is just syntactic sugar
const initialState = [
{
type: 'div',
class: 'foo',
},
{
type: 'div',
class: 'foo',
}
];
const nextState = [
{
type: 'div',
class: 'foo open',
innerHTML: 'bla',
},
{
type: 'div',
class: 'foo',
innerHTML: 'bla',
}
];
function generateDOM(stateToRender) {
// we now use a direct reference
const newRoot = document.createElement('div');
for (const i in stateToRender) {
if (!stateToRender.hasOwnProperty(i)) {
continue;
}
newRoot.appendChild(createElement(stateToRender[i]));
}
return newRoot;
}
function createElement(entry) {
let element = null;
if (!entry.type) {
element = document.createElement('div');
} else {
element = document.createElement(entry.type);
delete entry.type;
}
for (let i in entry) {
if (!entry.hasOwnProperty(i)) continue;
if ( typeof i !== "string") continue;
switch (i) {
case 'key': // we ignore the unique identifier inside of the meta DOM
break;
case 'children':
let children = entry[i];
for (let x in children){
if (!children.hasOwnProperty(x)) continue;
element.appendChild(createElement(entry[x]));
}
break;
default:
if (element[i] !== undefined) {
element[i] = entry[i];
}
break;
}
}
return element;
}
function updateDom(insertElement, documentFragment) {
if (insertElement.children.length > 0) {
for (let i = 0; i < insertElement.children.length; i++) {
insertElement.removeChild(insertElement.children[i]);
}
}
insertElement.appendChild(documentFragment);
}
document.addEventListener('DOMContentLoaded', function(){
const insertionPoint = document.getElementById('insertion-point');
const initialDOM = generateDOM(initialState);
const nextDOM = generateDOM(nextState);
// this is a side-effect
updateDom(insertionPoint, initialDOM);
// this only screws up direct references
for (let i = 0; i < initialDOM.children.length; i++) {
initialDOM.children[i].innerHTML = 'omg such sideffects';
}
setTimeout(
function() {
updateDom(insertionPoint, nextDOM)
},
1000
);
});
</script>
<html><body><div id="insertion-point"></div></body>
Without unwanted side effects: (createDocumentFragment)
<script>
'use strict';
// that is a meta DOM
// JSX is just syntactic sugar
const initialState = [
{
type: 'div',
class: 'foo',
},
{
type: 'div',
class: 'foo',
}
];
const nextState = [
{
type: 'div',
class: 'foo open',
innerHTML: 'bla',
},
{
type: 'div',
class: 'foo',
innerHTML: 'bla',
}
];
function generateDOM(stateToRender) {
// we now use a direct reference
const newRoot = document.createDocumentFragment();
for (const i in stateToRender) {
if (!stateToRender.hasOwnProperty(i)) {
continue;
}
newRoot.appendChild(createElement(stateToRender[i]));
}
return newRoot;
}
function createElement(entry) {
let element = null;
if (!entry.type) {
element = document.createElement('div');
} else {
element = document.createElement(entry.type);
delete entry.type;
}
for (let i in entry) {
if (!entry.hasOwnProperty(i)) continue;
if ( typeof i !== "string") continue;
switch (i) {
case 'key': // we ignore the unique identifier inside of the meta DOM
break;
case 'children':
let children = entry[i];
for (let x in children){
if (!children.hasOwnProperty(x)) continue;
element.appendChild(createElement(entry[x]));
}
break;
default:
if (element[i] !== undefined) {
element[i] = entry[i];
}
break;
}
}
return element;
}
function updateDom(insertElement, documentFragment) {
if (insertElement.children.length > 0) {
for (let i = 0; i < insertElement.children.length; i++) {
insertElement.removeChild(insertElement.children[i]);
}
}
insertElement.appendChild(documentFragment);
}
document.addEventListener('DOMContentLoaded', function(){
const insertionPoint = document.getElementById('insertion-point');
const initialDOM = generateDOM(initialState);
const nextDOM = generateDOM(nextState);
// this is a side-effect
updateDom(insertionPoint, initialDOM);
// this only screws up direct references
for (let i = 0; i < initialDOM.children.length; i++) {
initialDOM.children[i].innerHTML = 'omg such sideffects';
}
setTimeout(
function() {
updateDom(insertionPoint, nextDOM)
},
1000
);
});
</script>
<html><body><div id="insertion-point"></div></body>
the documentFragments are empty after appending so basically they are for the mutation calculations and everything besided the DOM be GCed afterwards.
so a low memory footprint. The main idea of react in the beginning was "no-sideffects" and "low amount of paints" (paint is the rerender)
<script>
'use strict';
// that is a meta DOM
// JSX is just syntactic sugar
const stateProgressions = [
[
{
type: 'div',
class: 'foo',
},
{
type: 'div',
class: 'foo',
}
],
[
{
type: 'div',
class: 'foo open',
innerHTML: 'bla',
},
{
type: 'div',
class: 'foo',
innerHTML: 'bla',
}
],
[
{
type: 'div',
class: 'foo open',
innerHTML: 'bla blub',
},
{
type: 'div',
class: 'foo',
innerHTML: 'bla blub',
}
],
[
{
type: 'div',
class: 'foo open',
innerHTML: 'bla blub bleh',
},
{
type: 'div',
class: 'foo',
innerHTML: 'bla blub bleh',
}
]
];
function generateDOM(stateToRender) {
// we now use a direct reference
const newRoot = document.createDocumentFragment();
for (const i in stateToRender) {
if (!stateToRender.hasOwnProperty(i)) {
continue;
}
newRoot.appendChild(createElement(stateToRender[i]));
}
return newRoot;
}
function createElement(entry) {
let element = null;
if (!entry.type) {
element = document.createElement('div');
} else {
element = document.createElement(entry.type);
delete entry.type;
}
for (let i in entry) {
if (!entry.hasOwnProperty(i)) continue;
if ( typeof i !== "string") continue;
switch (i) {
case 'key': // we ignore the unique identifier inside of the meta DOM
break;
case 'children':
let children = entry[i];
for (let x in children){
if (!children.hasOwnProperty(x)) continue;
element.appendChild(createElement(entry[x]));
}
break;
default:
if (element[i] !== undefined) {
element[i] = entry[i];
}
break;
}
}
return element;
}
function updateDom(insertElement, documentFragment) {
if (insertElement.children.length > 0) {
for (let i = 0; i < insertElement.children.length; i++) {
insertElement.removeChild(insertElement.children[i]);
}
}
insertElement.appendChild(documentFragment);
}
document.addEventListener('DOMContentLoaded', function(){
const insertionPoint = document.getElementById('insertion-point');
let myTimeout = null;
for (let i = 0; i < stateProgressions.length; i++) {
if (myTimeout) { // we prevent excessive repaints
clearTimeout(myTimeout);
}
// this is a side-effect
myTimeout = setTimeout(() => {
updateDom(insertionPoint, generateDOM(stateProgressions[i]));
}, 0)
}
});
</script>
<html><body><div id="insertion-point"></div></body>
with the the classic dedup async setting a timeout to zero -> pushing it on the eventloop and just adding the next state we only have actually 1 paint instead of 4.
this is a really trivial I know. coming back to
Modify WHAT "direct API" directly... what does some API even have to do with the subject unless the API itself is in fact rubbish by introducing problems that shouldn't even exist in the first place? ... and if it IS some API or framework or what-have-you causing these problems, why the hell would anyone be using them in the first place apart from a complete ignorance of how to use JavaScript in a client-side environment?
in code:
// direct api access
// as you know every exposed method/function is
// per definition the API
let element = document.createElement('div');
element.id = '12';
// it needs to be parsed before I can access the ID so
// no direct access to the api before the dom has actually been
// rendered
let element2 = '<div id="12"></div>";
but you already know this. Is the DOM-API rubbish ? depends on the usecase I guess.
... and all instances of the DOM are huge JavaScript objects, that's kind of the point. Is that the point people are missing when they start throwing the words "virtual" in there when that's a nonsensical distinction? Just because you made your own instance or fragment separate from a live one doesn't make it "virtual" or any other such nonsense!
the virtual DOM is just a meta representation of the DOM ... so as I wrote in the examples above. virtual just means IT IS NOT THE ACTUAL DOM that's all it's it just another representation of the DOM that you can access and modified without implicitly triggering a repaint. and if you look it up in the dictionary VIRTUAL is the a correct description.
Likewise the buzzwords "concurrency" and "functional" in practice -- for me at least -- mean NOTHING apart from trying to shoehorn fixed concepts into fitting every problem, instead of using the best tool at hand for the job. SOUNDS much like derpitude of trying to shoe-horn event driven language concepts like MVC into linear execution user called languages like PHP. That it can be done at all is more a testament to persistence and determination than it is rational thought.
I come from distributed large architectures to me functional programming and concurrency strategies are daily topics if you don't have such issues, good for you!
An MVC does not have to be event driven it's a basic architectural pattern it does not have the single controller pattern with an dispatcher concept underneath. That's specific common implementation but not every framework/lib does it.
I hope the code is at least a little clearer you can copy and paste it as an html and compare it directly. And I don't want to argue about why it's crap pls :D you asked me for examples, I gave you examples with comments on the side-effects.
Yes in the end those frameworks are for sloppy developers so they don't have to know that much to deliver an application ;D .... no shit sherlock ;D
I'm not really seeing what would be causing problems apart from your node flush being rubbish that would skip deleting nodes. That's not a DOM issue that's just rubbish code. THIS:
function updateDom(insertElement, documentFragment) {
if (insertElement.children.length > 0) {
for (let i = 0; i < insertElement.children.length; i++) {
insertElement.removeChild(insertElement.children[i]);
}
}
insertElement.appendChild(documentFragment);
}
Combined with WASTING TIME building that 'children' property in the first place is just pointless garbage and again, building an Array or nodeList instead of just using the bloody DOM correctly!
function updateDom(insertElement, documentFragment) {
while (insertElement.firstChild)
insertElement.removeChild(insertElement.firstChild);
insertElement.appendChild(documentFragment);
}
Much better. Gets rid of the 'variables for nothing' too. I really don't "get" the point of "let", NOT that I can even use it in the environments I program.
You also have a bug in your create Element for children. You wanted children[x] not entry[x]... and you couldn't actually use it to make INPUT which is why using 'type' instead of 'tagName' is rubbish. Much less not having it's own 'children' property your make would never assign any attributes (pointless 'continue's.)
NOT that I would really ever use DOMContentLoaded since generally speaking the DOM should be present if you move the script right before </body> where it generally belongs for both sanity and usability... unless your intent is to trigger it more than once which is something I would advise against doing; if you're updating the DOM yourself you don't need to trap that crap. Just put a self instancing function before </body> to isolate the scope and be done with it!
Made WORSE by the fact that you're NOT using the DOM since your 'side effect' IS USING INNERHTML! Much less you've put it on the DOM directly, what did you EXPECT it to do other than be a live copy?!? That's the POINT!
Where you commented "this is a side effect" and "screws up references" that's not a side effect or screwing up anything, that's HOW/WHY YOU USE IT! I'm still asking "What side effects?!?" after running either of those... or at least once I fixed them so they're operating on valid markup so that <html> is open FIRST like it should be... and having a doctype, etc, etc...
Unless I'm completely missing your usage case, neither of those is anything I would be putting on a website in that fashion in the first place. I would NOT be screwing around with DOMContentLoaded, I would NOT be using innerHTML, I would NOT have some pointless timeout (unless ... did you have that in there to simulate some other event?)... and if I append I fully well expect the initial reference to be live, THAT'S THE POINT!
The terminology across the whole thing seems utterly banjaxed too... you're calling nodes a 'DOM' or fragments, creating functions with the same names as existing methods confusing matters...
NOT helping are the things so new in JavaScript I would NEVER use them in deployment since they flat out won't exist client-side for a good swath of the users I serve.
That "in code" part with the the create vs the string -- the latter is the one I would be having problems with because it's some dipshit string I can't assign stuff to, and not the ACTUAL element node I can make changes/additions to. In that case it LITERALLY reads like you are saying all the advantages are a problem and all the problems are an advantage!
... and again whatever the blazes ANY of that has to do with an "API" is utterly beyond me. I have ZERO clue what ANY of that has to even do with the term.
IF I'm understanding the first snippet properly, this is how I'd have written it:
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8">
</head><body><div id="insertionPoint"></div><script>
(function(d) {
"use strict";
var
initialState = [
{
tagName : 'div',
className : 'foo'
},{
tagName : 'div',
className : 'foo'
}
],
nextState = [
{
tagName : 'div',
className : 'foo open',
content : 'bla'
}, {
tagName : 'div',
className : 'foo',
content : 'bla'
}
],
insertionPoint = d.getElementById('insertionPoint');
function nodeMake(entry) {
var e = d.createElement(entry.tagName ? entry.tagName : 'div');
for (var i in entry) {
switch (i) {
case 'content':
e.appendChild(
entry[i] instanceof Array?
make(entry[i]) :
d.createTextNode(entry[i])
);
case 'tagName':
break;
case 'style':
for (var j in entry[i]) e.style[j] = entry[i][j];
break;
case 'type':
// legacy IE screws up direct assignment on type so use setter
e.setAttribute(i, entry[i]);
break;
default:
// but legacy IE screws up other attributes on set...
e[i] = entry[i];
}
}
return e;
}
function nodeFlushChildren(e) {
while (e.firstChild) e.removeChild(e.firstChild);
}
function nodeReplaceChildren(parent, newChild) {
nodeFlushChildren(parent);
parent.appendChild(
'object' == typeof newChild ? newChild : d.createTextNode(newChild)
);
}
function nodeAppendFromArray(parent, entries) {
for (var i = 0, entry; entry = entries[i]; i++)
parent.appendChild(nodeMake(entry));
}
function nodeWalkChildren(parent, callback) {
var e = parent.firstElementChild;
while (e) {
callback(e);
e = e.nextElementSibling;
};
}
nodeAppendFromArray(insertionPoint, initialState);
nodeWalkChildren(insertionPoint, function(e) {
nodeReplaceChildren(e, 'what side effects?!?');
});
setTimeout(function() {
nodeFlushChildren(insertionPoint);
nodeAppendFromArray(insertionPoint, nextState);
}, 1000);
})(document);
</script></body></html>
I'm not even sure I'm understanding the point of the second one.
Jason Knight :D I'm not bored enough to continue this conversation g since you obviously don't want to understand but just complain gg and yes a 15 minute prototype has bugs gg no shit g and no using innerHTML does not matter because i use text nodes but this whole discusion is about you beeing right not about you trying to understand :D
But I like your implementation :)
j Well, just answer me this then, WHAT IS THE SIDE EFFECT? You have a comment about it in your code and I'm just not seeing the problem you are saying is there. What is it doing or not doing it should be? Running both I see zero difference apart from gross inefficiencies either way.
That's the question I keep asking, have been asking for a few years, and nobody seems to be able to actually explain how/what/where there is ACTUALLY a problem!
I'm TRYING to understand it, but nobody seems to be using words that mean anything or code that presents a relevant answer.
Jason Knight I've answered you several times. I even gave you code examples. and so i will boil it down. references per definition are side-effects.
the documentCreateFragment moves the content so accessing it afterwards has no side-effects. the createElement references the nodes and every modification of this part modifies the DOM.
and innerHTML was not relevant in this case because it was just to demonstrate that the first code executed will change the content in front of your eyes with the for loop and the second won't. That was all it was for. one time sideffects one time no sideeffects.
If that's sloppy or not I don't care one time something can happen the other time I don't have to worry about it. both is a trade as always speed vs stability.
It's a behaviour that can lead to complications if the code gets complex. no sideeffects just means "whatever happens in this function, stays this function" that is one of the real premisses functional programming is built on "COPY not REFERENCE".
That's it.
Ok, I ALMOST think I'm getting what you are saying, but what you are calling a "side effect" is the intentional effect I would use it for, leaving me wondering in what possible situation would you actually want it the other way around?
I'm not seeing the usage scenario where that would make a difference, or even where I'd want the behavior you are calling the opposite of a "Side effect". You write to the DOM the change takes place now, so everything else can see it now. Why you wouldn't want it now, much less while screwing with the DOM you'd try to isolate variables inside the function that don't matter anyways when the function ends...
No, I'm still not getting it. Though... hmm... you do build both node trees FIRST even before the second is needed -- whereas I would build it on the fly AS needed so that if I wanted I could change the data in the arrays for a new node tree instead of trying to modify an existing node tree... since if I wanted to modify it in a node tree I'd do it on the live DOM since that's what it's for.
I think we just have such radically different approaches to solving problems that we might as well be speaking two different languages. To my mindset what you are describing as a side-effect is what I would want on purpose. ALL THE TIME. Otherwise you're just making things harder later on -- particularly if there's a lot of data flow/handling.
Jason Knight the word is defined as side-effect in this context because you change something outside the function. that's the whole meaning and it's a precisely coined term not about intention.
Javascript is Object oriented hence it uses references for memory optimizations it's logical that they use it. but from a functional perspective it's still a side-effect and side-effect is nothing bad per se it's just something that happens sometimes you want side-effects and sometimes you don't.
Actually gg I just picked the functional approach because you asked for it. I'm not dogmatic, I like programming and I like understanding stuff that's it. I just wanted to explain the reasoning behind that approach and what they wanted to achieve and why the picked the approach.
there is a talk about this from facebook where they explained that after a while the code base got so big they had so many side-effects from so many different modules and libraries that every change did screw up something somewhere else. That's why they were going for the functional idea of "no side-effects".
Tbh. :D I wanted to build the reference based optimizations you implicated where i directly attach an element to the meta-object so I really just change what's needed when it's needed.
I even have several models in mind for that, I usually write libraries and frameworks so I usually have several ideas about implementations,
But I have to work _gg _so I cannot write 5 different solution and go into detail of all behavioural effects of the implementations and intentions. And I just wanted to bring the point across which obviously failed miserably ;D
Yeah, I'm not big on the current hot and trendy (and also poorly named) "functional programming" because it doesn't work how I think, how I learned to program, how I've spent four decades programming... and for me it creates more problems than it solves.
But then I tend to use a few dozen lines of JavaScript on production sites where most people use hundreds, avoiding most of those headaches by again treating JS as an enhancement to already working scripting-free pages, instead of going the "screw users with disabilities" approach of making sites that ONLY work with JS enabled.
One of the reasons a lot of people I know hate and will not use Facebook. JUST like they flat out would not use hashnode or quora or a slew of other sites as the "JavaScript for f*** off" approach to development has them saying "fine, f*** you too!"
Every time I look at these complex JS codebases all I can think is either "I could do this in a tenth the code" or "why the hell are you telling users to sod off?" Again what I've always said about the mental midgetry that is jQuery as what people do with it invariably falls into one of three categories.
What I've seen people build with systems like React, angular, and vue -- much less what I've cleaned up / eliminated for clients -- generally follows the same design pattern of what I would consider outright ineptitude.
Even as the people making them spout big words that don't mean anything like we're playing a game of bullshit bingo.
I understand :D but FP is old it got put down for a long time because memory was expensive and other classic religious fights between rivaling approaches of "how to control global state"
OOP took the "we control who change what" aka "messaging (private, protected, friend, public ....) and FP the "we just don't use the global state, everything is a copy" aka no "no global state inside a function" approach.
The lack of "memory / cpu" based thinking based on the "lets push this to the client" attitude as well as the newer compilers with better GCs and Heuristics for branch optimizations as well as the container based hybrid apps for mobile phones pushed a lot of it to. I think you observed this too.
A lot of solutions are just throwing a nuke onto something where a firecracker would've done the job.
I totally agree with you about those things ;D I use no-script as a default and just allow certain pages and scripts to run and it annoys me.
Still I will follow every trend to understand it because it does not matter if I like something, I need to understand it ... that's a requirement to myself. If it's good .... that I don't know ... it's just how I approach information, I need to dissect and understand it.
And yes some devs just use FP without knowing what the core principle of FP architecture- and memory-wise ... they probably don't understand OOP either ... a lot of BS all around.
Anyhow ... I'm rambling ;)