JavaScript patterns chapter 8 of mine

Preview:

Citation preview

DOM and Browser PatternsCarl

2016/02/23

1

Outline

Separation of Concerns

DOM Scripting

Events

Long-Running Scripts

Remote Scripting

Deploying JavaScript

Loading Strategies

Summary2

Separation of Concerns

Content

HTML

Presentation

CSS

Behavior

JavaScript

3

Separation of Concerns

Test without CSS/JS

No inline event handlers or style(?)

ReactJS JSX: <button onClick={this.test(this)}>Submit</button>

Semantically HTML elements

4

Capability Detection

Check function exist instead of check browser agent

// antipatternif (navigator.userAgent.indexOf('MSIE') !== −1) { document.attachEvent('onclick', console.log); }

// betterif (document.attachEvent) { document.attachEvent('onclick', console.log); }// or even more specificif (typeof document.attachEvent !== "undefined") { document.attachEvent('onclick', console.log); } 5

DOM Scriping

DOM Access

DOM Manipulation

6

DOM Access

Avoiding DOM access in loops

Assigning DOM references to local variables and working with the locals

Using selectors API where available

Caching the length when iterating over HTML collections (see Chapter 2)

7

Avoiding DOM access in loops// antipatternfor (var i = 0; i < 100; i += 1) { document.getElementById("result").innerHTML += i + ", "; }// better - update a local variablevar i, content = "";for (i = 0; i < 100; i += 1) { content += i + ","; }document.getElementById("result").innerHTML += content;

8

Assigning DOM references to local variables and working with the locals

// antipatternvar padding = document.getElementById("result").style.padding,margin = document.getElementById("result").style.margin;

// bettervar style = document.getElementById("result").style,padding = style.padding,margin = style.margin;

9

Using selectors API where availabledocument.querySelector("ul .selected");document.querySelectorAll("#widget .class");https://developer.mozilla.org/zh-TW/docs/Web/API/document.querySelector

Faster than jQuery Dom method

document.getElementById(myid) is still the fatest

https://jsperf.com/getelementbyid-vs-queryselector/25

10

DOM Manipulation(Document Fragment)// antipattern// appending nodes as they are createdvar p, t;p = document.createElement('p');document.body.appendChild(p);p = document.createElement('p');document.body.appendChild(p);

11

DOM Manipulation(Document Fragment)var p, t, frag;frag = document.createDocumentFragment();p = document.createElement('p');frag.appendChild(p);p = document.createElement('p');frag.appendChild(p);document.body.appendChild(frag);

https://developer.mozilla.org/en-US/docs/Web/API/Document/createDocumentFragment

12

DOM Manipulation(Document Fragment)var oldnode = document.getElementById('result'), clone = oldnode.cloneNode(true); // cloneNode(true) if the children of the node should also be cloned, or false to clone only the specified node. https://developer.mozilla.org/en-US/docs/Web/API/Node/cloneNode

// work with the clone...

// when you're done:oldnode.parentNode.replaceChild(clone, oldnode);

13

Events

Events Handling

Event Delegation

14

Events Handling

Use addEventListener/attachEvent instead of onxxx(ex: onclick)

onxxx bind to only one event

15

Event Delegation

Bind event to parent instead of child

Use event.target to check the target node

Pros

reduce event listeners

Cons

hard to find the event listener from browser developer tool

Demo

http://codepen.io/anon/pen/vLqvaV 16

Event Delegation

ReactJS JSX: <button onClick={this.test(this)}>Submit</button>

React use single top level event listener

https://facebook.github.io/react/docs/interactivity-and-dynamic-uis.html#under-the-hood-autobinding-and-event-delegation

17

Long-Running Scripts (setTimeout)

var timer1 = setTimeout(myfunction1, 50);var timer2 = setTimeout(myfunction2, 100);var timer3 = setTimeout(myfunction3, 150);

18

Long-Running Scripts (Web Wrokers)var ww = new Worker('my_web_worker.js'); ww.onmessage = function (event) { document.body.innerHTML += "<p>message from the background thread: " + event.data + "</p>";

};

// Outputmessage from the background thread: hello theremessage from the background thread: halfway there, `tmp` is now 3749999975000001message from the background thread: all done

19

// my_web_worker.jsvar end = 1e8, tmp = 1;postMessage('hello there');while (end) { end -= 1; tmp += end; if (end === 5e7) { // 5e7 is the half of 1e8 postMessage('halfway there, `tmp` is now ' + tmp); }}postMessage('all done');

Remote Scripting

XMLHttpRequest

JSONP

Frames and Image Beacons

20

XMLHttpRequestvar xhr = new XMLHttpRequest();xhr.onreadystatechange = function () { if (xhr.readyState !== 4) { // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState return false; } if (xhr.status !== 200) { alert("Error, status code: " + xhr.status); return false; } document.body.innerHTML += "<pre>" + xhr.responseText + "<\/pre>"; };xhr.open("GET", "page.html", true); xhr.send("");

21

JSONPNot restricted by the same-domain policy (Use script tag)

Often JSON wrapped in a function call

https://zh.wikipedia.org/wiki/JSONP

var script = document.createElement("script"); script.src = “http://remote.org/getdata.php?callback=myHandler”; document.body.appendChild(script);

// Output of http://example.org/getdata.php?callback=myHandlermyHandler({“hello”: “world”});

22