So far, we have talked mostly about programming on the server-side.
We can't ignore how important the server is: it's the only thing you can rely on for security, data storage, etc.
But, logic can also be embedded in HTML and executed by the user's browser.
In theory, any language could be used. In practice, we're limited by browser support.
That limits our language choices: JavaScript or something compiled to WebAssembly.
Like with HTML and CSS, we are relying on the user's browser to run the JavaScript code. That means…
You're going to find yourself looking at compatibility tables in docs again.
The <script>
tag can be used to reference an external JS file:
<script src="codefile.js"></script>
Or you can include JS code inline:
<script> /* code goes here */ </script>
Or really inline:
<a href="javascript:…" onclick="…"></a>
Putting JS code in your HTML (or HTML templates) is probably a bad idea.
<script>
in a page).Content-Security-Policy
header, which will prevent inline code from running for XSS mitigation. Prevents both <script>…</script>
and <a href="javascript:…">
.i<10 && j>0
, the corresponding HTML is i&lt;10 &amp;&amp; j>0
.Possible exception: short setup code, especially with a parameter from a template.
<script src="/code/main.js"></script> <script nonce="dbc67568b4c7f1ea541e"> var data_id = {{ dataobject.id }}; setup_this_page(data_id); </script>
Will still have Content-Security-Policy
problems (unless you add a nonce
to it). Impact on caching is minimal.
But probably you don't need the inline JS and can include the info you need safely:
<script id="some-data" type="application/json">…</script> …<body data-id="{{ dataobject.id }}">
… and then read them in JS.
function setup_this_page() { var my_id = document.querySelector('body').dataset.id; var some_data = JSON.parse( document.getElementById('some-data').textContent); ⋮
The Document Object Model (DOM) is a standard API to manipulate HTML/XML documents.
e.g. grab every <li>
from within a particular <ul>
and collect the contents.
e.g. find the element with id="foo"
and change its contents.
DOM gives a standard object-oriented way to access and manipulate an XML document. It's independent of programming language: can use in JavaScript, Python, Java, Ruby, ….
It provides a standard object-hierarchy (classes, method, etc) to represent and manipulate XML data.
The DOM is useful in many programming languages, but central to [client-side] JavaScript.
The JavaScript code lives inside an HTML page, so the DOM is an obvious way to access the page from within code.
There is a global object document
that is the DOM document object for the current page.
It's a DOM Document object and the entry point for DOM functionality.
For example, get a collection (a DOM NodeList or HTMLCollection) of all paragraphs on the page, or all elements with class="interesting"
:
var pars = document.getElementsByTagName('p'); var ints = document.getElementsByClassName('interesting');
The .querySelector()
and .querySelectorAll()
methods were added in DOM4/Selectors API and are implemented in modern browsers. They take a CSS selector and return NodeList.
var pars = document.querySelectorAll('p'); var ints = document.querySelectorAll('.interesting'); var inter_pars = document.querySelectorAll('p.interesting');
… like you thought you needed jQuery for (but more verbose, and maybe faster?).
The DOM API can also manipulate the document in-place.
var body = document.querySelector('body'); var new_p = document.createElement('p'); new_p.appendChild(document.createTextNode("I'm some text")); body.appendChild(new_p);
But the equivalent with jQuery is:
$('body').append("<p>I'm some text</p>")
One of the tricks JavaScript can do: make an HTTP request.
This opens up a huge variety of techniques: your code can contact the server to get/send information whenever it wants, and update the page as a result.
Techniques that use server interaction are often called AJAX: Asynchronous JavaScript And XML.
There is an XMLHttpRequest
object that makes all of this possible: it contains methods for making an HTTP request and dealing with the results.
You may see XHR as an abbreviation for this object and/or AJAX stuff.
Processing the results is done with a callback function: the JS process doesn't prevent other code from running while waiting for the response: non-blocking IO.
Using the XMLHttpRequest
object manually is a little clumsy. *
function reqListener() { data = JSON.parse(this.responseText); console.log(data["stuff"]); } var oReq = new XMLHttpRequest(); oReq.addEventListener("load", reqListener); oReq.open("GET", "http://example.com/data.json"); oReq.send();
It's more common to let a library simplify things. With jQuery.ajax
:
$.ajax('http://example.com/data.json', { dataType: 'json', success: function(data, status, xhr) { console.log(data['stuff']); } });
Plus: error handling etc. is much more straightforward.
An AJAX request can be used to fetch data from, or send data to the server (or any combination). Some ways that can be used:
It is common to want to get real-time updates from the server. To do that, the server would have to send new info whenever it's available.
e.g. chat app; live news feed; real-time game between users.
Real-time communication isn't what HTTP was designed for, and it's a bad fit.
Option 1: poll. Client makes a request (with XMLHttpRequest
) every few seconds asking for new info. Lots of overhead in requests/bandwidth.
Option 2: long-polling. Client makes an HTTP connection, the server waits until it has some new info to report and then responds.
Requires many open TCP connections on the server. Most server software isn't good at that.
Option 3: WebSockets. If HTTP isn't the right protocol for the job, use a different one.
The WebSockets protocol lets servers and clients exchange data in either direction. The interface is more low-level than XHR interactions: you can .send()
and set an .onmessage
handler.
It's probably much easier to use a library like Socket.IO to work with WebSockets.
The server-side programming model is usually “how do I respond to a request?” Now it has to be “some new data has arrived, who should I send it to?” That's going to require a big change (at least for that part of the site).
or graceful degradation if you're a pessimist.
We need to arrange our site/app so the content works in whatever situation we send it to: modern desktop browser, smartphone browser, Google, other automated tool, …
We need to structure the page so that any of these can make sense of the content, as best possible with the capabilities they have.
e.g. Google only cares about content, so is more interested in your HTML: it should be able to get useful info out of just that.
e.g. Chrome should be able to do all of the JavaScript stuff you want.
The underlying structure of the web helps here:
The technologies have been designed with this in mind.
e.g. for an <input>
, the default type is type="text"
. If you use <input type="date">
in a browser that doesn't support it, it will just look like a text input.
On browsers that support it, you get a nice date selector, including something media-appropriate on a mobile or other non-desktop browser.
Of course, you must validate input server-side anyway.
Code your sites with progressive enhancement in mind.
You should have an idea of what HTML/CSS/JavaScript features are going to work in various browsers. Think about what happens to the site if individual features don't work.
Test in as many different situations as possible.
I prefer to think of JavaScript as a way to enhance pages: start with a functional page/site that can be used without JavaScript. Use JavaScript to make it better.
e.g. in browsers where your JavaScript library can build a date selector, turn it on. In other browsers, the user gets a text input, which is okay.
This line of thinking can extend to mobile/desktop development.
Start with a site that works well on desktop/mobile, then enhance so it's better on mobile/desktop. That could involve CSS or JavaScript tweaks for either scenario.
JavaScript itself is basically just a programming language. It's not perfect.
There are many common problems that aren't solved by built-in language features, but you don't want to solve yourself.
The solution is the same as always: libraries and frameworks (≈big libraries).
There is a huge variety of JavaScript libraries. I'll make some attempt to categorize them…
The most basic libraries just fix things “wrong” with the language.
e.g. simplify DOM work, AJAX, event handling; extra types/collections.
jQuery seems to be the winner here.
Others do specialized jobs.
Cookie
header.… and thousands of others available from npm.
The “frameworks” tend to be bigger and influence most/all of your JS code.
Again, there's a lot of variety in what gets called a JavaScript framework
. Just like with server-side frameworks, programmers sometimes forget they have a programming language available and can just program: not everything has to be a framework call.
In general they handle some of these steps: server API ↔ HTTP+JSON ↔ objects ↔ display for user.
Don't forget that server API
part means you're going to have to create a server API.
API ↔ HTTP+JSON ↔ objects: getting data between the server (in the DB) and client (in objects we can work with). A lot like an ORM.
e.g. Backbone.js, Meteor, Ember Data.
Objects ↔ display for user: how/when to we update the page for the user? How do we update our objects when the user does things? Data binding
.
Will likely include some kind of template rendering, which indicates how objects will turn into HTML.
Aside… If we're displaying objects for the user, that's content = a resource = something that should have a URL.
Some frameworks help connect display of data to usable URLs. Watch for that.
That's obviously all over-simplified. All of the frameworks do much more than that. Some really badly; some really awesomely.
Remember the technology evaluation? Hopefully that had useful details.
JavaScript has a lot of things in its favour:
So why not use JavaScript on the server-side as well?
You could have only one (programming) language for your project: easier source management, fewer skills needed when hiring, etc.
Can re-use code on both sides.
For example, input validation. You want to make sure users enter the correct format in the browser for nice UI, but must check it on the server for security/correctness.
If you have anything but JS on the server-side, you need to write the logic twice (or do some transpiling magic).
This thinking leads to Meteor which is a both a server- and client-side framework.
But on the server, you have the choice of any programming language you want. Is JavaScript really the best one in the world?
Wouldn't you rather write Python/Scala/Groovy/Erlang?
So is server-side JavaScript a good idea?
Maybe.