Practical JavaScript Programming Session 5 Wilson Su
2 https://www.slideshare.net/sweekson/
3 Wilson Su Front-end Developer, HIE ● 6 years in web design ● Specialize in JavaScript / CSS / HTML / OOP / Git ● Familiar with PHP / Design Pattern ● Interested in UI & Ix Design wilson_su@trend.com.tw
Outline 4 Practical JavaScript Programming Chapter 9. ● Form Elements ● Form Events ● Access Form Data ● Validations ● Custom Components Forms Chapter 10. AJAX ● What’s AJAX? ● Handle Request ● Security ● Practices ● Promise ● Server-sent Events ● WebSocket
Chapter 9. Forms 5
Form Elements 6
HTML Form Elements 7 1. <input type="text" value="initial value"/> 2. <input type="password"/> 3. <input type="checkbox" value="abc" checked/> 4. <input type="radio" value="xyz" checked/> 5. <input type="file" multiple/> 6. <input type="hidden"/> 7. <select multiple> 8. <option value="1">1</option> 9. <option value="2" selected>2</option> 10. <option value="3">3</option> 11. </select> 12. <textarea cols="30" rows="5">initial value</textarea>
HTML Buttons 8 1. <input type="button" value="Action"/> 2. <input type="submit" value="Submit"/> 3. <input type="reset" value="Reset"/> 4. <button type="button">Action</button> 5. <button type="submit">Submit</button> 6. <button type="reset">Reset</button>
HTML <form> Element With GET Method 9 1. <form action="/search" method="get"> 2. <input name="query" type="text" value="keywords"/> 3. <button type="submit">Search</button> 4. </form> 5. <!-- When the form is submitted, the URL will be generated as '/search?query=keywords' -->
HTML <form> Element With POST Method 10 1. <form action="/login" method="post"> 2. <label for="user">Username:</label> 3. <input id="user" name="user" type="text" value="guest"/> 4. <label for="pass">Password:</label> 5. <input id="pass" name="pass" type="password" value="12345"/> 6. <button type="submit">Sign In</button> 7. </form> 8. <!-- When the form is submitted, the request body be generated as 'user=guest&pass=12345' -->
Compare GET VS. POST 11 Form Elements GET POST Requests data from a specified resource Submits data to be processed to a specified resource Can be bookmarked Cannot be bookmarkedBookmarked Can be cached Not cachedCached Data is visible to everyone in the URL Data is not displayed in the URLVisibility Harmless Data will be re-submittedBACK button / Reload The length of a URL is limited No restrictionsMax URL length
Form Events 12
Event Delegator 13 1. function delegator (elem) { 2. return function (type, selectors, fn, capture) { 3. function matches (target) { 4. return selectors.some(v => target.matches(v)); 5. } 6. function listener (e) { 7. matches(e.target) && fn.call(e.target, e); 8. } 9. selectors = selectors.split(/,s*/g); 10. elem.addEventListener(type, listener, capture); 11. return listener; 12. }; 13. }
HTML <input> Events 14 1. var query = document.querySelector('input#query'); 2. var logger = function (e) { console.log(e.type); } 3. query.addEventListener('focus', logger); 4. query.addEventListener('input', logger); 5. query.addEventListener('blur', logger); 6. query.addEventListener('change', logger); 7. query.addEventListener('keydown', logger); 8. query.addEventListener('keypress', logger); 9. query.addEventListener('keyup', logger); 10. /* When the input has focus, and user typed one letter */ 11. // 'focus', 'keydown', 'keypress', 'input', 'keyup' 12. /* When the input has lost focus */ 13. // 'change', 'blur'
Focus Events 15 1. <input id="name" type="text"/> 2. <script> 3. var name = document.querySelector('#name'); 4. name.addEventListener('focus', (e) => console.log(e.type)); 5. name.addEventListener('blur', (e) => console.log(e.type)); 6. name.addEventListener('focusin', (e) => console.log(e.type)); 7. name.addEventListener('focusout', (e) => console.log(e.type)); 8. /* When the input has focus */ 9. // 'focus', 'focusin' 10. /* When the input has lost focus */ 11. // 'blur', 'focusout' 12. </script>
The input focus and blur event does not bubble. 16
The focus and blur Event Does Not Bubble 17 1. <form id="edit"><input id="address" type="text"/></form> 2. <script> 3. var edit = document.querySelector('#edit'); 4. var name = document.querySelector('#address'); 5. var onFocus = function (e) { 6. console.log(e.currentTarget.tagName, e.type); 7. }; 8. edit.addEventListener('focus', onFocus); 9. edit.addEventListener('blur', onFocus); 10. name.addEventListener('focus', onFocus); 11. name.addEventListener('blur', onFocus); 12. // 'INPUT' 'focus', 'INPUT' 'blur' 13. </script>
Selecting Text on Focus 18 1. <input type="text" value="Hello"/> 2. <textarea cols="30" rows="5">Aloha</textarea> 3. <script> 4. var body = document.body; 5. var selectors = 'input[type="text"], textarea'; 6. var onFocus = function (e) { e.target.select(); }; 7. delegator(body)('focusin', selectors, onFocus); 8. delegator(body)('focus', selectors, onFocus, true); 9. </script>
Filtering a List Using input Event 19 1. <input id="filter" type="text"/> 2. <div id="output"></div> 3. <script> 4. var filter = document.querySelector('#filter'); 5. var output = document.querySelector('#output'); 6. var items = ['JS', 'JAVA', 'PHP', 'NODEJS']; 7. filter.addEventListener('input', function (e) { 8. output.textContent = items.filter(item => { 9. return item.indexOf(e.target.value) > -1; 10. }); 11. }); 12. </script>
HTML Form submit and reset Events 20 1. <form id="atm" action="/transfer"> 2. <input id="pass" type="password"/> 3. <button type="submit">Enter</button> 4. <button type="reset">Clear</button> 5. </form> 6. <script> 7. var atm = document.querySelector('#atm'); 8. var logger = function (e) { console.log(e.type); }; 9. atm.addEventListener('submit', logger); 10. atm.addEventListener('reset', logger); 11. // 'reset', 'submit' 12. </script>
Access Form Data 21
Assigning Default Values 22 1. <form action="/order" method="post"> 2. Amount: <input id="amount" type="text"/> 3. <input id="dm" type="checkbox"/> Send me DM 4. <button type="submit">Save</button> 5. <button type="reset">Reset</button> 6. </form> 7. <script> 8. document.querySelector('#amount').value = 0; 9. document.querySelector('#dm').checked = true; 10. /* The input.value will be reset to empty after the Reset button has been clicked. Use input.defaultValue to assign a default value. Use input.defaultChecked for checkbox and radio */ 11. </script>
Getting and Setting Values of Input Text and Textarea 23 1. <input id="name" type="text" value="Ben"/> 2. <textarea id="intro" cols="10" rows="5">Ben is a RD</textarea> 3. <script> 4. var name = document.querySelector('#name'); 5. var intro = document.querySelector('#intro'); 6. console.log(name.value); // 'Ben' 7. console.log(intro.value); // 'Ben is a RD' 8. name.value = 'Vicky'; 9. intro.value = 'Vicky is a VD'; 10. </script>
Getting Values of Checked Checkboxes 24 1. <input name="order" id="1" type="checkbox" value="50" checked> 2. <label for="1">French fries</label> 3. <input name="order" id="2" type="checkbox" value="30" checked> 4. <label for="2">Sprite</label> 5. <script> 6. var selector = '[name="order"]:checked'; 7. var selected = document.querySelectorAll(selector); 8. var values = [...selected].map(elem => elem.value); 9. var total = values.reduce((a, b) => +a + +b); 10. console.log(total); // 80 11. </script>
Setting checked to a Checkbox 25 1. <input id="enabled" type="checkbox" checked/> 2. <script> 3. var enabled = document.querySelector('#enabled'); 4. console.log(enabled.value); // 'on' 5. console.log(enabled.hasAttribute('checked')); // true 6. console.log(enabled.checked); // true 7. 8. enabled.checked = false; 9. console.log(enabled.hasAttribute('checked')); // true 10. console.log(enabled.getAttribute('checked')); // '' 11. </script>
Getting and Setting Value of Radio Button Group 26 1. <form name="profile"> 2. <input name="gender" type="radio" value="M" checked/> Male 3. <input name="gender" type="radio" value="F"/> Female 4. </form> 5. <script> 6. var selector = '[name="gender"]:checked'; 7. var selected = document.querySelector(selector); 8. console.log(selected.value); // 'M' 9. console.log(document.forms.profile.gender.value); // 'M' 10. document.forms.profile.gender.value = 'F'; 11. </script>
Getting Selected Value of a Select 27 1. <select id="lang"> 2. <option value="en-US">English</option> 3. <option value="zh-TW" selected>繁體中文</option> 4. </select> 5. <script> 6. var lang = document.querySelector('#lang'); 7. var options = lang.options; 8. console.log(lang.value); // 'zh-TW' 9. console.log(lang.selectedIndex); // 1 10. console.log(options[lang.selectedIndex].text); // '繁體中文' 11. lang.value = 'en-US'; 12. console.log(options[1].selected); // false 13. </script>
Getting Selected Values of a Multiple Select 28 1. <select id="beverage" multiple> 2. <option value="tea" selected>Tea</option> 3. <option value="soda">Soda</option> 4. <option value="coffee" selected>Coffee</option> 5. </select> 6. <script> 7. var beverage = document.querySelector('#beverage'); 8. var options = drink.options; 9. var selected = [...options].filter(o => o.selected); 10. var values = selected.map(o => o.value); 11. console.log(values); // (2) ['tea', 'coffee'] 12. </script>
Serializing Form Data - Snippet 1/2 29 1. <form id="edit"> 2. <input type="text" name="text" value="1"/> 3. <input type="checkbox" name="checkbox" value="2" checked/> 4. <input type="checkbox" name="checkbox" value="3" checked/> 5. <input type="radio" name="radio" value="4"/> 6. <input type="radio" name="radio" value="5" checked/> 7. <select name="select"> 8. <option value="6">6</option> 9. <option value="7" selected>7</option> 10. </select> 11. <textarea name="textarea" cols="30" rows="5">8</textarea> 12. <button type="submit">Submit</button> 13. </form>
Serializing Form Data - Snippet 2/2 30 1. function serialize (form) { 2. var key, val, output = [...form.elements].map(elem => { 3. key = elem.name, val = elem.value; 4. if (elem.type === 'checkbox' || elem.type === 'radio') { 5. val = elem.checked ? val : null; 6. } 7. if (!key || val === null) { return false; } 8. return `${key}=${val}`; 9. }); 10. return output.filter(v => v).join('&'); 11. } 12. console.log(serialize(document.querySelector('#edit'))); 13. // 'text=1&checkbox=2&checkbox=3&radio=5&select=7&textarea=8'
Validations 31
Disable browser default validations. 32
HTML <form> novalidate Attribute 33 1. <form action="/login" method="post" novalidate> 2. Username: <input name="user" type="text" required/> 3. Password: <input name="pass" type="password" required/> 4. <button type="submit">Sign In</button> 5. </form>
Checking Required Fields 34 1. <form id="login" action="/login" method="post" novalidate> 2. Username: <input name="user" type="text" required/> 3. Password: <input name="pass" type="password" required/> 4. <button type="submit">Sign In</button> 5. </form> 6. <script> 7. var login = document.querySelector('#login'), required; 8. login.addEventListener('submit', function (e) { 9. required = document.querySelectorAll(':required'); 10. if ([...required].filter(el => !el.value).length) { 11. e.preventDefault(); 12. } 13. }); 14. </script>
Preventing User From Typing Non-numeric Values 35 1. <input id="phone" type="text"/> 2. <script> 3. var phone = document.querySelector('#phone'); 4. phone.addEventListener('keypress', function (e) { 5. if (e.key && !/^[0-9]+$/.test(e.key)) { 6. e.preventDefault(); 7. } 8. }); 9. </script>
Preventing Form Submission Using onsubmit Attribute 36 1. <form action="/login" onsubmit="return onSignin(event);"> 2. Username: <input id="user" type="text"/> 3. Password: <input id="pass" type="password"/> 4. <button type="submit">Sign In</button> 5. </form> 6. <script> 7. var user = document.querySelector('#user'); 8. var pass = document.querySelector('#pass'); 9. function onSignin (e) { 10. return !!user.value && !!pass.value; 11. } 12. </script>
Preventing Form Submission Using Event Handler 37 1. <form id="login" action="/login"> 2. Username: <input id="user" type="text"/> 3. Password: <input id="pass" type="password"/> 4. <button type="submit">Sign In</button> 5. </form> 6. <script> 7. var login = document.querySelector('#login'); 8. var user = document.querySelector('#user'); 9. var pass = document.querySelector('#pass'); 10. login.addEventListener('submit', function onSignin (e) { 11. (!user.value || !pass.value) && e.preventDefault(); 12. }); 13. </script>
Custom Components 38
Combo Box 39 Custom Components A combo box allows the user to type in a single-line input to limit the search, and select an item from a list of matched options. Combo box interaction specs ( incomplete ) : ● Click the caret button to open options ● Type keywords to filter options ● Arrow buttons to highlight an option ● Press enter to set value with the highlighted option ● Click cancel button to clear search
40 Date Picker The date picker contains the date input field and the calendar view. Users can either use the input field to type a date or by selecting a date in the calendar. Date picker interaction specs ( incomplete ) : ● Focus input to open a canlendar ● Press keyboard arrows to switch year, month, and date ● Click arrows to switch months ● Click a date to set value Custom Components
Chapter 10. AJAX 41
What’s AJAX? 42
AJAX 43 ● AJAX is an acronym for Asynchronous JavaScript and XML ● It is a web technique that allows for more interactivity by making web pages that fetch data in the background and alter themselves without reloading the entire page. ● A user can continue to use the application while the client program requests information from the server in the background. What’s AJAX?
A Traditional Web Application 44 What’s AJAX? Client Server User Interface Web Server Data Beckend HTTP Request HTML + CSS + JS
An AJAX Web Application 45 What’s AJAX? User Interface Web Server Data BeckendAJAX Engine Client Server HTTP Request JS Call Data Data (XML / TEXT / HTML / JSON)
Handle Request 46
Making an AJAX Request 47 1. var xhr = new XMLHttpRequest(); 2. xhr.onreadystatechange = function () { 3. if (xhr.readyState === xhr.DONE && xhr.status === 200) { 4. console.log(xhr.responseText); 5. // <button id="{{id}}" type="button">{{action}}</button> 6. } 7. }; 8. xhr.open('get', '/templates/button.html', true); 9. xhr.send();
Making a Synchronous Request 48 1. var xhr = new XMLHttpRequest(); 2. xhr.open('GET', '/data/cars.json', false); 3. xhr.send(); 4. console.log(xhr.responseText); 5. // '["audi","benz","bmw"]'
Synchronous XMLHttpRequest makes the JavaScript stop executing until the server response is ready. If the server is busy or slow, the application will hang or stop. 49
Wrapping XMLHttpRequest 50 1. function request (method, url, callback) { 2. var xhr = new XMLHttpRequest(); 3. xhr.onreadystatechange = function () { 4. if (xhr.readyState === xhr.DONE && xhr.status === 200) { 5. callback instanceof Function && callback(this); 6. } 7. }; 8. xhr.open(method, url, true); 9. return xhr; 10. } 11. /* Usage */ 12. // request('get', '/data/cars.json', (xhr) => { … }).send();
Handling the Server Response 51 1. request('get', '/data/numbers.json', function (xhr) { 2. console.log(xhr.status); // 200 3. console.log(xhr.statusText); // 'OK' 4. console.log(xhr.responseText); // '[100,200,300]' 5. console.log(xhr.getResponseHeader('Content-type')); 6. // 'application/json' 7. }) 8. .send();
Working with XML Data 52 1. /* Given a XML file 'food.xml' as follows: 2. <?xml version="1.0" encoding="UTF-8"?> 3. <root><food>Pizza</food><food>Bread</food></root> 4. */ 5. request('get', '/data/food.xml', function (xhr) { 6. var nodes = xhr.responseXML.getElementsByTagName('food'); 7. var data = [...nodes].map(node => node.textContent); 8. console.log(data); // (2) ['Pizza', 'Bread'] 9. }) 10. .send();
Using POST Method in XMLHTTPRequest 53 1. var item = 'item=iphone'; 2. var amount = 'amount=99'; 3. var params = [item, amount].join('&'); 4. var contentType = 'application/x-www-form-urlencoded'; 5. var xhr = request('post', '/order', function (xhr) { 6. console.log(xhr.responseText); 7. // '{"data":{"item":"iphone","amount":"99"}}' 8. }); 9. xhr.setRequestHeader('Content-type', contentType); 10. xhr.send(params);
Encoding a URI Component 54 1. var hello = '你好'; 2. var param = 'text=' + encodeURIComponent(hello); 3. var url = '/echo?' + param; 4. request('get', url, function (xhr) { 5. console.log(xhr.responseText); // '你好' 6. }) 7. .send();
Uploading a File 55 1. <input id="file" type="file"/> 2. <script> 3. var file = document.querySelector('#file').files[0]; 4. var data = new FormData(); 5. var xhr = request('post', '/upload'); 6. data.append('target', 'images'); 7. data.append('file', file, 'sky.jpg'); 8. xhr.send(data); 9. </script>
Monitoring Progress of a File Upload 56 1. var file = document.querySelector('#file').files[0]; 2. var data = new FormData(); 3. var xhr = request('post', '/upload'); 4. data.append('file', file); 5. xhr.upload.addEventListener('progress', function (e) { 6. if (e.lengthComputable) { 7. console.log(Math.floor(e.loaded / e.total * 100)); 8. } 9. }); 10. xhr.send(data);
Security 57
AJAX requests are forbidden by default by the same-origin policy. 58
URL Outcome Reason http://www.abc.com/about/contact.html Success Same protocol, host and port http://www.abc.com/service/training.html Success Same protocol, host and port https://www.abc.com/member/login.html Failure Different protocol http://www.abc.com:8080/partners.html Failure Different port http://abc.com/blog/tags.html Failure Different host Same-origin Policy 59 The same-origin policy restricts how a document or script loaded from one origin can interact with a resource from another origin. The following table gives examples of origin comparisons to the URL http://www.abc.com/about/index.html: Security
Cross-Origin Resource Sharing CORS is a system, consisting of transmitting HTTP headers, that determines whether to block or fulfill requests for restricted resources on a web page from another domain outside the domain from which the resource originated. To allow any resource to access your resource, you can specify: Access-Control-Allow-Origin: * To allow https://www.abc.com to access your resource, you can specify: Access-Control-Allow-Origin: https://www.abc.com 60 Security
JSON with Padding 61 JSONP is used to request data from a server residing in a different domain than the client. JSONP Client Server <script>function fn (data) { … }</script> <script src="https://api.su.com/users/9?callback=fn"></script> response.setHeader('Content-type', 'text/javascript'); response.send('fn({ "id": 9, "name": "Kyle" })');
Practices 62
Polling 63 1. function Polling (options) { 2. this.url = options.url; 3. this.method = options.method || 'get'; 4. this.callback = options.callback || (() => {}); 5. this.delay = options.delay || 1000; 6. this.start(); 7. } 8. Polling.prototype.start = function () { 9. setTimeout(() => { 10. request(this.method, this.url, this.callback).send(); 11. this.start(); 12. }, this.delay); 13. };
Checking Username Availability 64 1. var account = document.querySelector('input#account'); 2. var defer = function (fn) { 3. var timer; 4. return function (e) { 5. if (timer) { clearTimeout(timer); } 6. timer = setTimeout(() => fn.call(e.target, e), 300); 7. }; 8. }; 9. account.addEventListener('input', defer(function (e) { 10. request('get', '/api/users/check', () => {}); 11. }));
You don’t need AJAX to download a file. 65
Downloading a File 66 1. var url = 'https://locate/to/file'; 2. /* Solution 1 */ 3. location.assign(url); 4. 5. /* Solution 2 */ 6. window.open(url, '_blank'); 7. 8. /* Solution 3 (Better) */ 9. var iframe = document.createElement('iframe'); 10. iframe.style.display = 'none'; 11. iframe.src = url; 12. document.appendChild(iframe);
Disable action buttons while requesting to prevent user from re-submitting the form. 67
Disabling Submit Button When Request Is In-progress 68 1. var profile = document.querySelector('form#profile'); 2. var save = document.querySelector('[type="submit"]#save'); 3. profile.addEventListener('submit', function (e) { 4. e.preventDefault(); 5. request('post', 'submit', function (xhr) { 6. save.disabled = false; 7. }).send(); 8. save.disabled = true; 9. });
Callback Hell 69 1. /* Suppose url1, url2, url3, and success are defined */ 2. request('get', url1, function (xhr) { 3. request('get', url2, function (xhr) { 4. request('get', url3, function (xhr) { 5. success(); 6. }); 7. }); 8. });
Using Named Functions 70 1. /* Suppose url1, url2, url3, and success are defined */ 2. function doReq1 () { 3. request('get', url1, function () { doReq2(); }); 4. } 5. function doReq2 () { 6. request('get', url2, function () { doReq3(); }); 7. } 8. function doReq3 () { 9. request('get', url3, function () { success(); }); 10. } 11. doReq1();
Promise 71
What’s a Promise? 72 A Promise is an object representing the eventual completion or failure of an asynchronous operation. – MDN Promise Promise .then(onFulfilled) .catch(onRejected) Promise … pending resolved rejected pending return
Creating a Promise 73 1. new Promise(function (resolve, reject) { 2. setTimeout(() => resolve('Success!'), 1000); 3. }) 4. .then(function (message) { 5. console.log(message); // 'Success!' 6. return { message }; 7. }) 8. .then(function (data) { 9. console.log(data); // {message: 'Success!'} 10. }) 11. .catch(function (error) { 12. console.log(error); 13. });
Chaining after a catch 74 1. new Promise((resolve, reject) => { 2. console.log('initialized'); 3. resolve(); 4. }) 5. .then(() => { 6. throw new Error('something failed'); 7. console.log('success'); 8. }) 9. .catch((error) => console.log('failure')) 10. .then(() => console.log('Whatever happened before')); 11. // 'initialized', 'failure', 'Whatever happened before'
Wrapping AJAX Request with Promise 75 1. function ajax (method, url, data) { 2. return new Promise(function (resolve, reject) { 3. var xhr = new XMLHttpRequest(); 4. xhr.onreadystatechange = function () { 5. if (xhr.readyState === xhr.DONE) { 6. if (xhr.status === 200) { 7. resolve(JSON.parse(xhr.responseText)); 8. } else { reject(xhr.responseText); } 9. } 10. }; 11. xhr.open(method, url, true); 12. xhr.send(data); 13. }); 14. }
Making a Request With the Enhanced Request Function 76 1. ajax('post', '/api/order', { item: 'ipad', amount: 99 }) 2. .then(function (data) { 3. console.log(data); 4. }) 5. .catch(function (error) { 6. console.error(error); 7. });
Chaining Requests with Promises 77 1. /* Suppose url1, url2, url3, and success are defined */ 2. function doReq1 () { return ajax('get', url1); } 3. function doReq2 () { return ajax('get', url2); } 4. function doReq3 () { return ajax('get', url3); } 5. doReq1().then(doReq2).then(doReq3).then(success);
The Promise.all() Method 78 1. Promise.all([ 2. ajax('get', '/data/hosts.json'), 3. ajax('get', '/data/users.json') 4. ]) 5. .then(function ([hosts, users]) { 6. console.log(hosts); 7. console.log(users); 8. }) 9. .catch(function (error) { 10. console.error(error); 11. });
The fetch API 79 1. var data = new FormData(); 2. data.append('action', 'cancel'); 3. 4. fetch('/orders/1', { method: 'POST', body: data }) 5. .then(function (response) { 6. // response.ok bool 7. // response.status number 8. // response.headers Headers 9. // response.json() Promise 10. }) 11. .catch(function (error) {});
Server-sent Events 80
Server-sent Events 81 SSE is a technology where a browser receives automatic updates from a server via HTTP connection. – Wiki Request Response Request Response Handshake Acknowledgement Server push Server push CLIENT SERVER Polling CLIENT SERVER Server-sent Event VS.
Receiving Server-Sent Event Notifications 82 1. var es = new EventSource('http://localhost/stream'); 2. 3. es.addEventListener('open', function (e) { … }); 4. es.addEventListener('error', function (e) { … }); 5. es.addEventListener('message', function (e) { 6. console.log(JSON.parse(e.data)); 7. }); 8. es.addEventListener('custom-event', function (e) { 9. console.log(JSON.parse(e.data)); 10. });
WebSocket 83
WebSocket is a computer communications protocol, providing full-duplex communication channels over a single TCP connection. – Wiki What Is WebSocket? 84 WebSocket Request Response Request Response Handshake Acknowledgement Bi-directional messages Connection end CLIENT SERVER HTTP CLIENT SERVER WebSocket VS. Connection lifecycle Connection lifecycle
Creating a WebSocket Object 85 1. var ws = new WebSocket('wss://localhost'); 2. 3. ws.addEventListener('open', function (e) { … }); 4. ws.addEventListener('error', function (e) { … }); 5. ws.addEventListener('message', function (e) { 6. console.log(JSON.parse(e.data)); 7. // { success: true, action: 'echo', data: 'Bye' } 8. ws.close(); 9. }; 10. ws.send(JSON.stringify({ action: 'echo', data: 'Bye' }));
Reference 86 ● Ajax (programming) - Wikipedia ● CORS - Glossary | MDN ● Cross-origin resource sharing - Wikipedia ● GET vs POST - Difference and Comparison | Diffen ● JavaScript | MDN ● JSONP - Wikipedia Practical JavaScript Programming
Reference ● Same-origin policy - Wikipedia ● Same-origin policy - Web security | MDN ● Server-sent events - Wikipedia ● WebSocket - Wikipedia 87 Practical JavaScript Programming
Questions? 88
THANKS

Practical JavaScript Programming - Session 5/8

  • 1.
  • 2.
  • 3.
    3 Wilson Su Front-end Developer,HIE ● 6 years in web design ● Specialize in JavaScript / CSS / HTML / OOP / Git ● Familiar with PHP / Design Pattern ● Interested in UI & Ix Design wilson_su@trend.com.tw
  • 4.
    Outline 4 Practical JavaScript Programming Chapter9. ● Form Elements ● Form Events ● Access Form Data ● Validations ● Custom Components Forms Chapter 10. AJAX ● What’s AJAX? ● Handle Request ● Security ● Practices ● Promise ● Server-sent Events ● WebSocket
  • 5.
  • 6.
  • 7.
    HTML Form Elements 7 1.<input type="text" value="initial value"/> 2. <input type="password"/> 3. <input type="checkbox" value="abc" checked/> 4. <input type="radio" value="xyz" checked/> 5. <input type="file" multiple/> 6. <input type="hidden"/> 7. <select multiple> 8. <option value="1">1</option> 9. <option value="2" selected>2</option> 10. <option value="3">3</option> 11. </select> 12. <textarea cols="30" rows="5">initial value</textarea>
  • 8.
    HTML Buttons 8 1. <inputtype="button" value="Action"/> 2. <input type="submit" value="Submit"/> 3. <input type="reset" value="Reset"/> 4. <button type="button">Action</button> 5. <button type="submit">Submit</button> 6. <button type="reset">Reset</button>
  • 9.
    HTML <form> ElementWith GET Method 9 1. <form action="/search" method="get"> 2. <input name="query" type="text" value="keywords"/> 3. <button type="submit">Search</button> 4. </form> 5. <!-- When the form is submitted, the URL will be generated as '/search?query=keywords' -->
  • 10.
    HTML <form> ElementWith POST Method 10 1. <form action="/login" method="post"> 2. <label for="user">Username:</label> 3. <input id="user" name="user" type="text" value="guest"/> 4. <label for="pass">Password:</label> 5. <input id="pass" name="pass" type="password" value="12345"/> 6. <button type="submit">Sign In</button> 7. </form> 8. <!-- When the form is submitted, the request body be generated as 'user=guest&pass=12345' -->
  • 11.
    Compare GET VS.POST 11 Form Elements GET POST Requests data from a specified resource Submits data to be processed to a specified resource Can be bookmarked Cannot be bookmarkedBookmarked Can be cached Not cachedCached Data is visible to everyone in the URL Data is not displayed in the URLVisibility Harmless Data will be re-submittedBACK button / Reload The length of a URL is limited No restrictionsMax URL length
  • 12.
  • 13.
    Event Delegator 13 1. functiondelegator (elem) { 2. return function (type, selectors, fn, capture) { 3. function matches (target) { 4. return selectors.some(v => target.matches(v)); 5. } 6. function listener (e) { 7. matches(e.target) && fn.call(e.target, e); 8. } 9. selectors = selectors.split(/,s*/g); 10. elem.addEventListener(type, listener, capture); 11. return listener; 12. }; 13. }
  • 14.
    HTML <input> Events 14 1.var query = document.querySelector('input#query'); 2. var logger = function (e) { console.log(e.type); } 3. query.addEventListener('focus', logger); 4. query.addEventListener('input', logger); 5. query.addEventListener('blur', logger); 6. query.addEventListener('change', logger); 7. query.addEventListener('keydown', logger); 8. query.addEventListener('keypress', logger); 9. query.addEventListener('keyup', logger); 10. /* When the input has focus, and user typed one letter */ 11. // 'focus', 'keydown', 'keypress', 'input', 'keyup' 12. /* When the input has lost focus */ 13. // 'change', 'blur'
  • 15.
    Focus Events 15 1. <inputid="name" type="text"/> 2. <script> 3. var name = document.querySelector('#name'); 4. name.addEventListener('focus', (e) => console.log(e.type)); 5. name.addEventListener('blur', (e) => console.log(e.type)); 6. name.addEventListener('focusin', (e) => console.log(e.type)); 7. name.addEventListener('focusout', (e) => console.log(e.type)); 8. /* When the input has focus */ 9. // 'focus', 'focusin' 10. /* When the input has lost focus */ 11. // 'blur', 'focusout' 12. </script>
  • 16.
    The input focusand blur event does not bubble. 16
  • 17.
    The focus andblur Event Does Not Bubble 17 1. <form id="edit"><input id="address" type="text"/></form> 2. <script> 3. var edit = document.querySelector('#edit'); 4. var name = document.querySelector('#address'); 5. var onFocus = function (e) { 6. console.log(e.currentTarget.tagName, e.type); 7. }; 8. edit.addEventListener('focus', onFocus); 9. edit.addEventListener('blur', onFocus); 10. name.addEventListener('focus', onFocus); 11. name.addEventListener('blur', onFocus); 12. // 'INPUT' 'focus', 'INPUT' 'blur' 13. </script>
  • 18.
    Selecting Text onFocus 18 1. <input type="text" value="Hello"/> 2. <textarea cols="30" rows="5">Aloha</textarea> 3. <script> 4. var body = document.body; 5. var selectors = 'input[type="text"], textarea'; 6. var onFocus = function (e) { e.target.select(); }; 7. delegator(body)('focusin', selectors, onFocus); 8. delegator(body)('focus', selectors, onFocus, true); 9. </script>
  • 19.
    Filtering a ListUsing input Event 19 1. <input id="filter" type="text"/> 2. <div id="output"></div> 3. <script> 4. var filter = document.querySelector('#filter'); 5. var output = document.querySelector('#output'); 6. var items = ['JS', 'JAVA', 'PHP', 'NODEJS']; 7. filter.addEventListener('input', function (e) { 8. output.textContent = items.filter(item => { 9. return item.indexOf(e.target.value) > -1; 10. }); 11. }); 12. </script>
  • 20.
    HTML Form submitand reset Events 20 1. <form id="atm" action="/transfer"> 2. <input id="pass" type="password"/> 3. <button type="submit">Enter</button> 4. <button type="reset">Clear</button> 5. </form> 6. <script> 7. var atm = document.querySelector('#atm'); 8. var logger = function (e) { console.log(e.type); }; 9. atm.addEventListener('submit', logger); 10. atm.addEventListener('reset', logger); 11. // 'reset', 'submit' 12. </script>
  • 21.
  • 22.
    Assigning Default Values 22 1.<form action="/order" method="post"> 2. Amount: <input id="amount" type="text"/> 3. <input id="dm" type="checkbox"/> Send me DM 4. <button type="submit">Save</button> 5. <button type="reset">Reset</button> 6. </form> 7. <script> 8. document.querySelector('#amount').value = 0; 9. document.querySelector('#dm').checked = true; 10. /* The input.value will be reset to empty after the Reset button has been clicked. Use input.defaultValue to assign a default value. Use input.defaultChecked for checkbox and radio */ 11. </script>
  • 23.
    Getting and SettingValues of Input Text and Textarea 23 1. <input id="name" type="text" value="Ben"/> 2. <textarea id="intro" cols="10" rows="5">Ben is a RD</textarea> 3. <script> 4. var name = document.querySelector('#name'); 5. var intro = document.querySelector('#intro'); 6. console.log(name.value); // 'Ben' 7. console.log(intro.value); // 'Ben is a RD' 8. name.value = 'Vicky'; 9. intro.value = 'Vicky is a VD'; 10. </script>
  • 24.
    Getting Values ofChecked Checkboxes 24 1. <input name="order" id="1" type="checkbox" value="50" checked> 2. <label for="1">French fries</label> 3. <input name="order" id="2" type="checkbox" value="30" checked> 4. <label for="2">Sprite</label> 5. <script> 6. var selector = '[name="order"]:checked'; 7. var selected = document.querySelectorAll(selector); 8. var values = [...selected].map(elem => elem.value); 9. var total = values.reduce((a, b) => +a + +b); 10. console.log(total); // 80 11. </script>
  • 25.
    Setting checked toa Checkbox 25 1. <input id="enabled" type="checkbox" checked/> 2. <script> 3. var enabled = document.querySelector('#enabled'); 4. console.log(enabled.value); // 'on' 5. console.log(enabled.hasAttribute('checked')); // true 6. console.log(enabled.checked); // true 7. 8. enabled.checked = false; 9. console.log(enabled.hasAttribute('checked')); // true 10. console.log(enabled.getAttribute('checked')); // '' 11. </script>
  • 26.
    Getting and SettingValue of Radio Button Group 26 1. <form name="profile"> 2. <input name="gender" type="radio" value="M" checked/> Male 3. <input name="gender" type="radio" value="F"/> Female 4. </form> 5. <script> 6. var selector = '[name="gender"]:checked'; 7. var selected = document.querySelector(selector); 8. console.log(selected.value); // 'M' 9. console.log(document.forms.profile.gender.value); // 'M' 10. document.forms.profile.gender.value = 'F'; 11. </script>
  • 27.
    Getting Selected Valueof a Select 27 1. <select id="lang"> 2. <option value="en-US">English</option> 3. <option value="zh-TW" selected>繁體中文</option> 4. </select> 5. <script> 6. var lang = document.querySelector('#lang'); 7. var options = lang.options; 8. console.log(lang.value); // 'zh-TW' 9. console.log(lang.selectedIndex); // 1 10. console.log(options[lang.selectedIndex].text); // '繁體中文' 11. lang.value = 'en-US'; 12. console.log(options[1].selected); // false 13. </script>
  • 28.
    Getting Selected Valuesof a Multiple Select 28 1. <select id="beverage" multiple> 2. <option value="tea" selected>Tea</option> 3. <option value="soda">Soda</option> 4. <option value="coffee" selected>Coffee</option> 5. </select> 6. <script> 7. var beverage = document.querySelector('#beverage'); 8. var options = drink.options; 9. var selected = [...options].filter(o => o.selected); 10. var values = selected.map(o => o.value); 11. console.log(values); // (2) ['tea', 'coffee'] 12. </script>
  • 29.
    Serializing Form Data- Snippet 1/2 29 1. <form id="edit"> 2. <input type="text" name="text" value="1"/> 3. <input type="checkbox" name="checkbox" value="2" checked/> 4. <input type="checkbox" name="checkbox" value="3" checked/> 5. <input type="radio" name="radio" value="4"/> 6. <input type="radio" name="radio" value="5" checked/> 7. <select name="select"> 8. <option value="6">6</option> 9. <option value="7" selected>7</option> 10. </select> 11. <textarea name="textarea" cols="30" rows="5">8</textarea> 12. <button type="submit">Submit</button> 13. </form>
  • 30.
    Serializing Form Data- Snippet 2/2 30 1. function serialize (form) { 2. var key, val, output = [...form.elements].map(elem => { 3. key = elem.name, val = elem.value; 4. if (elem.type === 'checkbox' || elem.type === 'radio') { 5. val = elem.checked ? val : null; 6. } 7. if (!key || val === null) { return false; } 8. return `${key}=${val}`; 9. }); 10. return output.filter(v => v).join('&'); 11. } 12. console.log(serialize(document.querySelector('#edit'))); 13. // 'text=1&checkbox=2&checkbox=3&radio=5&select=7&textarea=8'
  • 31.
  • 32.
  • 33.
    HTML <form> novalidateAttribute 33 1. <form action="/login" method="post" novalidate> 2. Username: <input name="user" type="text" required/> 3. Password: <input name="pass" type="password" required/> 4. <button type="submit">Sign In</button> 5. </form>
  • 34.
    Checking Required Fields 34 1.<form id="login" action="/login" method="post" novalidate> 2. Username: <input name="user" type="text" required/> 3. Password: <input name="pass" type="password" required/> 4. <button type="submit">Sign In</button> 5. </form> 6. <script> 7. var login = document.querySelector('#login'), required; 8. login.addEventListener('submit', function (e) { 9. required = document.querySelectorAll(':required'); 10. if ([...required].filter(el => !el.value).length) { 11. e.preventDefault(); 12. } 13. }); 14. </script>
  • 35.
    Preventing User FromTyping Non-numeric Values 35 1. <input id="phone" type="text"/> 2. <script> 3. var phone = document.querySelector('#phone'); 4. phone.addEventListener('keypress', function (e) { 5. if (e.key && !/^[0-9]+$/.test(e.key)) { 6. e.preventDefault(); 7. } 8. }); 9. </script>
  • 36.
    Preventing Form SubmissionUsing onsubmit Attribute 36 1. <form action="/login" onsubmit="return onSignin(event);"> 2. Username: <input id="user" type="text"/> 3. Password: <input id="pass" type="password"/> 4. <button type="submit">Sign In</button> 5. </form> 6. <script> 7. var user = document.querySelector('#user'); 8. var pass = document.querySelector('#pass'); 9. function onSignin (e) { 10. return !!user.value && !!pass.value; 11. } 12. </script>
  • 37.
    Preventing Form SubmissionUsing Event Handler 37 1. <form id="login" action="/login"> 2. Username: <input id="user" type="text"/> 3. Password: <input id="pass" type="password"/> 4. <button type="submit">Sign In</button> 5. </form> 6. <script> 7. var login = document.querySelector('#login'); 8. var user = document.querySelector('#user'); 9. var pass = document.querySelector('#pass'); 10. login.addEventListener('submit', function onSignin (e) { 11. (!user.value || !pass.value) && e.preventDefault(); 12. }); 13. </script>
  • 38.
  • 39.
    Combo Box 39 Custom Components Acombo box allows the user to type in a single-line input to limit the search, and select an item from a list of matched options. Combo box interaction specs ( incomplete ) : ● Click the caret button to open options ● Type keywords to filter options ● Arrow buttons to highlight an option ● Press enter to set value with the highlighted option ● Click cancel button to clear search
  • 40.
    40 Date Picker The datepicker contains the date input field and the calendar view. Users can either use the input field to type a date or by selecting a date in the calendar. Date picker interaction specs ( incomplete ) : ● Focus input to open a canlendar ● Press keyboard arrows to switch year, month, and date ● Click arrows to switch months ● Click a date to set value Custom Components
  • 41.
  • 42.
  • 43.
    AJAX 43 ● AJAX isan acronym for Asynchronous JavaScript and XML ● It is a web technique that allows for more interactivity by making web pages that fetch data in the background and alter themselves without reloading the entire page. ● A user can continue to use the application while the client program requests information from the server in the background. What’s AJAX?
  • 44.
    A Traditional WebApplication 44 What’s AJAX? Client Server User Interface Web Server Data Beckend HTTP Request HTML + CSS + JS
  • 45.
    An AJAX WebApplication 45 What’s AJAX? User Interface Web Server Data BeckendAJAX Engine Client Server HTTP Request JS Call Data Data (XML / TEXT / HTML / JSON)
  • 46.
  • 47.
    Making an AJAXRequest 47 1. var xhr = new XMLHttpRequest(); 2. xhr.onreadystatechange = function () { 3. if (xhr.readyState === xhr.DONE && xhr.status === 200) { 4. console.log(xhr.responseText); 5. // <button id="{{id}}" type="button">{{action}}</button> 6. } 7. }; 8. xhr.open('get', '/templates/button.html', true); 9. xhr.send();
  • 48.
    Making a SynchronousRequest 48 1. var xhr = new XMLHttpRequest(); 2. xhr.open('GET', '/data/cars.json', false); 3. xhr.send(); 4. console.log(xhr.responseText); 5. // '["audi","benz","bmw"]'
  • 49.
    Synchronous XMLHttpRequest makes theJavaScript stop executing until the server response is ready. If the server is busy or slow, the application will hang or stop. 49
  • 50.
    Wrapping XMLHttpRequest 50 1. functionrequest (method, url, callback) { 2. var xhr = new XMLHttpRequest(); 3. xhr.onreadystatechange = function () { 4. if (xhr.readyState === xhr.DONE && xhr.status === 200) { 5. callback instanceof Function && callback(this); 6. } 7. }; 8. xhr.open(method, url, true); 9. return xhr; 10. } 11. /* Usage */ 12. // request('get', '/data/cars.json', (xhr) => { … }).send();
  • 51.
    Handling the ServerResponse 51 1. request('get', '/data/numbers.json', function (xhr) { 2. console.log(xhr.status); // 200 3. console.log(xhr.statusText); // 'OK' 4. console.log(xhr.responseText); // '[100,200,300]' 5. console.log(xhr.getResponseHeader('Content-type')); 6. // 'application/json' 7. }) 8. .send();
  • 52.
    Working with XMLData 52 1. /* Given a XML file 'food.xml' as follows: 2. <?xml version="1.0" encoding="UTF-8"?> 3. <root><food>Pizza</food><food>Bread</food></root> 4. */ 5. request('get', '/data/food.xml', function (xhr) { 6. var nodes = xhr.responseXML.getElementsByTagName('food'); 7. var data = [...nodes].map(node => node.textContent); 8. console.log(data); // (2) ['Pizza', 'Bread'] 9. }) 10. .send();
  • 53.
    Using POST Methodin XMLHTTPRequest 53 1. var item = 'item=iphone'; 2. var amount = 'amount=99'; 3. var params = [item, amount].join('&'); 4. var contentType = 'application/x-www-form-urlencoded'; 5. var xhr = request('post', '/order', function (xhr) { 6. console.log(xhr.responseText); 7. // '{"data":{"item":"iphone","amount":"99"}}' 8. }); 9. xhr.setRequestHeader('Content-type', contentType); 10. xhr.send(params);
  • 54.
    Encoding a URIComponent 54 1. var hello = '你好'; 2. var param = 'text=' + encodeURIComponent(hello); 3. var url = '/echo?' + param; 4. request('get', url, function (xhr) { 5. console.log(xhr.responseText); // '你好' 6. }) 7. .send();
  • 55.
    Uploading a File 55 1.<input id="file" type="file"/> 2. <script> 3. var file = document.querySelector('#file').files[0]; 4. var data = new FormData(); 5. var xhr = request('post', '/upload'); 6. data.append('target', 'images'); 7. data.append('file', file, 'sky.jpg'); 8. xhr.send(data); 9. </script>
  • 56.
    Monitoring Progress ofa File Upload 56 1. var file = document.querySelector('#file').files[0]; 2. var data = new FormData(); 3. var xhr = request('post', '/upload'); 4. data.append('file', file); 5. xhr.upload.addEventListener('progress', function (e) { 6. if (e.lengthComputable) { 7. console.log(Math.floor(e.loaded / e.total * 100)); 8. } 9. }); 10. xhr.send(data);
  • 57.
  • 58.
    AJAX requests are forbiddenby default by the same-origin policy. 58
  • 59.
    URL Outcome Reason http://www.abc.com/about/contact.htmlSuccess Same protocol, host and port http://www.abc.com/service/training.html Success Same protocol, host and port https://www.abc.com/member/login.html Failure Different protocol http://www.abc.com:8080/partners.html Failure Different port http://abc.com/blog/tags.html Failure Different host Same-origin Policy 59 The same-origin policy restricts how a document or script loaded from one origin can interact with a resource from another origin. The following table gives examples of origin comparisons to the URL http://www.abc.com/about/index.html: Security
  • 60.
    Cross-Origin Resource Sharing CORSis a system, consisting of transmitting HTTP headers, that determines whether to block or fulfill requests for restricted resources on a web page from another domain outside the domain from which the resource originated. To allow any resource to access your resource, you can specify: Access-Control-Allow-Origin: * To allow https://www.abc.com to access your resource, you can specify: Access-Control-Allow-Origin: https://www.abc.com 60 Security
  • 61.
    JSON with Padding 61 JSONPis used to request data from a server residing in a different domain than the client. JSONP Client Server <script>function fn (data) { … }</script> <script src="https://api.su.com/users/9?callback=fn"></script> response.setHeader('Content-type', 'text/javascript'); response.send('fn({ "id": 9, "name": "Kyle" })');
  • 62.
  • 63.
    Polling 63 1. function Polling(options) { 2. this.url = options.url; 3. this.method = options.method || 'get'; 4. this.callback = options.callback || (() => {}); 5. this.delay = options.delay || 1000; 6. this.start(); 7. } 8. Polling.prototype.start = function () { 9. setTimeout(() => { 10. request(this.method, this.url, this.callback).send(); 11. this.start(); 12. }, this.delay); 13. };
  • 64.
    Checking Username Availability 64 1.var account = document.querySelector('input#account'); 2. var defer = function (fn) { 3. var timer; 4. return function (e) { 5. if (timer) { clearTimeout(timer); } 6. timer = setTimeout(() => fn.call(e.target, e), 300); 7. }; 8. }; 9. account.addEventListener('input', defer(function (e) { 10. request('get', '/api/users/check', () => {}); 11. }));
  • 65.
    You don’t needAJAX to download a file. 65
  • 66.
    Downloading a File 66 1.var url = 'https://locate/to/file'; 2. /* Solution 1 */ 3. location.assign(url); 4. 5. /* Solution 2 */ 6. window.open(url, '_blank'); 7. 8. /* Solution 3 (Better) */ 9. var iframe = document.createElement('iframe'); 10. iframe.style.display = 'none'; 11. iframe.src = url; 12. document.appendChild(iframe);
  • 67.
    Disable action buttonswhile requesting to prevent user from re-submitting the form. 67
  • 68.
    Disabling Submit ButtonWhen Request Is In-progress 68 1. var profile = document.querySelector('form#profile'); 2. var save = document.querySelector('[type="submit"]#save'); 3. profile.addEventListener('submit', function (e) { 4. e.preventDefault(); 5. request('post', 'submit', function (xhr) { 6. save.disabled = false; 7. }).send(); 8. save.disabled = true; 9. });
  • 69.
    Callback Hell 69 1. /*Suppose url1, url2, url3, and success are defined */ 2. request('get', url1, function (xhr) { 3. request('get', url2, function (xhr) { 4. request('get', url3, function (xhr) { 5. success(); 6. }); 7. }); 8. });
  • 70.
    Using Named Functions 70 1./* Suppose url1, url2, url3, and success are defined */ 2. function doReq1 () { 3. request('get', url1, function () { doReq2(); }); 4. } 5. function doReq2 () { 6. request('get', url2, function () { doReq3(); }); 7. } 8. function doReq3 () { 9. request('get', url3, function () { success(); }); 10. } 11. doReq1();
  • 71.
  • 72.
    What’s a Promise? 72 APromise is an object representing the eventual completion or failure of an asynchronous operation. – MDN Promise Promise .then(onFulfilled) .catch(onRejected) Promise … pending resolved rejected pending return
  • 73.
    Creating a Promise 73 1.new Promise(function (resolve, reject) { 2. setTimeout(() => resolve('Success!'), 1000); 3. }) 4. .then(function (message) { 5. console.log(message); // 'Success!' 6. return { message }; 7. }) 8. .then(function (data) { 9. console.log(data); // {message: 'Success!'} 10. }) 11. .catch(function (error) { 12. console.log(error); 13. });
  • 74.
    Chaining after acatch 74 1. new Promise((resolve, reject) => { 2. console.log('initialized'); 3. resolve(); 4. }) 5. .then(() => { 6. throw new Error('something failed'); 7. console.log('success'); 8. }) 9. .catch((error) => console.log('failure')) 10. .then(() => console.log('Whatever happened before')); 11. // 'initialized', 'failure', 'Whatever happened before'
  • 75.
    Wrapping AJAX Requestwith Promise 75 1. function ajax (method, url, data) { 2. return new Promise(function (resolve, reject) { 3. var xhr = new XMLHttpRequest(); 4. xhr.onreadystatechange = function () { 5. if (xhr.readyState === xhr.DONE) { 6. if (xhr.status === 200) { 7. resolve(JSON.parse(xhr.responseText)); 8. } else { reject(xhr.responseText); } 9. } 10. }; 11. xhr.open(method, url, true); 12. xhr.send(data); 13. }); 14. }
  • 76.
    Making a RequestWith the Enhanced Request Function 76 1. ajax('post', '/api/order', { item: 'ipad', amount: 99 }) 2. .then(function (data) { 3. console.log(data); 4. }) 5. .catch(function (error) { 6. console.error(error); 7. });
  • 77.
    Chaining Requests withPromises 77 1. /* Suppose url1, url2, url3, and success are defined */ 2. function doReq1 () { return ajax('get', url1); } 3. function doReq2 () { return ajax('get', url2); } 4. function doReq3 () { return ajax('get', url3); } 5. doReq1().then(doReq2).then(doReq3).then(success);
  • 78.
    The Promise.all() Method 78 1.Promise.all([ 2. ajax('get', '/data/hosts.json'), 3. ajax('get', '/data/users.json') 4. ]) 5. .then(function ([hosts, users]) { 6. console.log(hosts); 7. console.log(users); 8. }) 9. .catch(function (error) { 10. console.error(error); 11. });
  • 79.
    The fetch API 79 1.var data = new FormData(); 2. data.append('action', 'cancel'); 3. 4. fetch('/orders/1', { method: 'POST', body: data }) 5. .then(function (response) { 6. // response.ok bool 7. // response.status number 8. // response.headers Headers 9. // response.json() Promise 10. }) 11. .catch(function (error) {});
  • 80.
  • 81.
    Server-sent Events 81 SSE isa technology where a browser receives automatic updates from a server via HTTP connection. – Wiki Request Response Request Response Handshake Acknowledgement Server push Server push CLIENT SERVER Polling CLIENT SERVER Server-sent Event VS.
  • 82.
    Receiving Server-Sent EventNotifications 82 1. var es = new EventSource('http://localhost/stream'); 2. 3. es.addEventListener('open', function (e) { … }); 4. es.addEventListener('error', function (e) { … }); 5. es.addEventListener('message', function (e) { 6. console.log(JSON.parse(e.data)); 7. }); 8. es.addEventListener('custom-event', function (e) { 9. console.log(JSON.parse(e.data)); 10. });
  • 83.
  • 84.
    WebSocket is acomputer communications protocol, providing full-duplex communication channels over a single TCP connection. – Wiki What Is WebSocket? 84 WebSocket Request Response Request Response Handshake Acknowledgement Bi-directional messages Connection end CLIENT SERVER HTTP CLIENT SERVER WebSocket VS. Connection lifecycle Connection lifecycle
  • 85.
    Creating a WebSocketObject 85 1. var ws = new WebSocket('wss://localhost'); 2. 3. ws.addEventListener('open', function (e) { … }); 4. ws.addEventListener('error', function (e) { … }); 5. ws.addEventListener('message', function (e) { 6. console.log(JSON.parse(e.data)); 7. // { success: true, action: 'echo', data: 'Bye' } 8. ws.close(); 9. }; 10. ws.send(JSON.stringify({ action: 'echo', data: 'Bye' }));
  • 86.
    Reference 86 ● Ajax (programming)- Wikipedia ● CORS - Glossary | MDN ● Cross-origin resource sharing - Wikipedia ● GET vs POST - Difference and Comparison | Diffen ● JavaScript | MDN ● JSONP - Wikipedia Practical JavaScript Programming
  • 87.
    Reference ● Same-origin policy- Wikipedia ● Same-origin policy - Web security | MDN ● Server-sent events - Wikipedia ● WebSocket - Wikipedia 87 Practical JavaScript Programming
  • 88.
  • 89.