Notes from the course The Hard Parts of UI Development by Will Sentance in Frontendmasters.
Goal 1 - Display content on the screen
-
Layout engineworks out page layout for specific browser/screen. -
Render engineproduces the composite ‘image’ for graphics card. -
html>DOMinC++(webcore) > visual content.htmlis a one time addition of elements into the DOM. -
CSS>CSSOM(mirrors theDOM) inC++> styling the content above - Render engines creates an image of the page, which gets sent to the graphics card and updated 60 times a second.
Goal 2 - Let users change the content / interact with it
-
htmlis a one time addition of elements to theDOM(in C++). Changing content on the screen changes the DOM. However, we cannot run code on the DOM. Javascript is needed. - When we load a url in the browser: 1) we open the html file,
htmlis parsed by thehtml parserand creates the DOM (in C++); 2) the html file has a reference to the JS file, which will start loading by the JS engine, with its own thread of execution, memory, execution context, etc.; 3) JS links to the C++ DOM runtime via thedocumentobject and all the methods available to it:document.querySelector, etc. -
Web IDL(Interface Description Language) - standardised way to know how to access other parts of the browser from JS.DOM APIis written in human language - its implementation in the browser will be described in theWeb IDL. -
const jsDiv = document.querySelector('div')uses thedocumentobject, which will give us access to theDOM APIvia a hidden link to the C++ DOM. It will allow us to grab a list of elements in C++.jsDivwill be assigned to the evaluation ofdocument.querySelector('div'). That will be an object with properties that allow us to access and modify the C++ DOM element i.e.textContent. If we console log that element, instead of the C++ DOM element we get the html command that created the C++ DOM element! -
textContentis the property ofjsDivin the document object that will update the DOM So it is agetter setterproperty, otherwise it would be confined to this object and would be of little use to us.otherand others get added to the call stack. - The following code follows the steps described after:
// in app.html
<input />
<div></div>
<script src='app.js'></script>
// in app.js
let post = '';
const jsInput = document.querySelector('input');
const jsDiv = document.querySelector('div');
function handleInput() {
post = jsInput.value;
jsDiv.textContext = post;
}
jsInput.onInput = handleInput;
-
app.htmlloads; theHTML parserlooks at each line and adds them to the C++ DOM from which we will produce the actual pixels of the webpage through thelayout and render engine; theHTML parserwill tee up the JS engine to run; this will give us access to thedocumentobject that has a reference to the C++ object, that we can run function on to search or add elements. - There is a division between "C++ land" and JS land (we are not able to write code directly into the C++ land. Once the HTML is parsed and the items added in the C++ object, the items appear in the screen.
- When JS starts executing, we get a call stack and a global execution context, which has a pre-loaded object:
document. This object allow our JS to interact with the C++ object:querySelector(this is one type ofaccessor object), etc. They not only have action in JS but also in the C++ object. - The JS above: 1) define const post assigned to empty string 2)
document.querySelector('input')will call thequerySelectorgetter/setter in the document object, which will bring us to the C++ object 3) it finds it but because the C++ object cannot be brought back a corresponding object gets produced in JS with a link to the underlying C++ object; 4) that newly produced object is assigned tojsInput; 5) that JS object has properties that will allow us to work with the C++ object: i.e.onInput,value, etc.; 6) same forjsDiv; 7) assignhandleInputto a function declaration; 8) in thejsInputJS object representation of the C++ element we will use the setteronInputto assign it to the function declarationhandleInput. That will add a handler in the C++ element that will trigger the execution of that function when a user inputs something in theinputC++ object element; 9) user action writes something in the input (ie. "Hi") and that triggers aneventwhich issues a command to the C++ element to execute its handler; 10)valuein theinputC++ element will be populated withHi; 11) the Events API will trigger the function referenced in the C++ element handler and add the call tohandleInputin the callback queue; 12) theevent loopwill grab that function execution from the callback queue when the call stack is empty and there i no more JS code to run in the global execution context; 13) the function call will be added it to thecall stack; 14) anexecution contextwill be created with its memory; 15) in memory the variablepostwill be assigned to the value of the propertyvalueof thejsInputobject; 16) we look inside thejsDivobject for the settertextContextwhich is set to the value ofpost; 17)textContentupdates the value of the underlying C++ element, which in turn updates the screen to show "Hi".
One-way data binding
- It is a paradigm implemented by the frameworks (React, Vue, Angular, etc.) that restrict the back and forth between C++ and JS to make our lives easier as UI engineers.
- Code:
// in app.html
<input />
<div></div>
<script src='app.js'></script>
// in app.js
let post = '';
const jsInput = document.querySelector('input');
const jsDiv = document.querySelector('div');
jsInput.value = 'What is on your mind?'; // view
function handleInput() {
post = jsInput.value;
jsDiv.textContext = post; // affect view!
}
function handleClick() {
jsInput.value = ''; // affect view!
}
jsInput.onInput = handleInput;
jsInput.onClick = handleClick;
-
jsInput.valuesets the C++ value to the value set in JS and that renders the string in the screen; user action click input: sends an event to the DOM to trigger the handler which adds the function to the JS callback queue; event loop grabs thehandleClickand adds it to the call stack;handleClickis called and an execution context is created; thevaluesetter ofjsInputgets sets to an empty string, updates the value in the C++ element, which updates the string; next user action: input; they will write whatever, which will trigger the C++ element handler, add the function to the callback queue, event loop will add it to the call stack, new execution context, thevalueproperty of thejsInputobject will be assigned topost, and that string will be set to thetextContentsetter, which updates the C++ element, which updates the screen.
Top comments (0)