55
Bài giảng Phát triển ứng dụng web Lê Đình Thanh VNU-UET FIT Email: [email protected] Mobile: 0987.257.504 Website: https://uet.vnu.edu.vn/~thanhld 1

Bài giảng Phát triển ứng dụng web - iTest

  • Upload
    others

  • View
    8

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Bài giảng Phát triển ứng dụng web - iTest

Bài giảng

Phát triển ứng dụng web

Lê Đình Thanh

VNU-UET FIT

Email: [email protected]

Mobile: 0987.257.504

Website: https://uet.vnu.edu.vn/~thanhld

1

Page 2: Bài giảng Phát triển ứng dụng web - iTest

JavaScript nâng cao

Lập trình không đồng bộ

Vòng lặp sự kiện

Xử lý song song

Web API

2Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 3: Bài giảng Phát triển ứng dụng web - iTest

Lập trình đồng bộ Một tác vụ đang xử lý thì phải xử lý xong (kết thúc),

tác vụ khác mới có thể chạy được.

Mỗi thời điểm chỉ có nhiều nhất một tác vụ được xử lý (đơn nhiệm - singletasking)

Khi ứng dụng web thực hiện tác vụ mất thời gian và không trả điều khiển cho trình duyệt

trình duyệt bị khóa/treo/đóng băng (blocking/frozen/unresponding)

người dùng không tương tác được3

Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Task A Task B Task C

time

Page 4: Bài giảng Phát triển ứng dụng web - iTest

Ví dụ lập trình đồng bộ

4

function sFunction () { return ("Hello S!"); }

console.log("begin");

let ret = sFunction();

console.log(ret);

console.log("end");

Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

beginHello S!end

Page 5: Bài giảng Phát triển ứng dụng web - iTest

Lập trình không đồng bộ Một tác vụ đang chạy có thể bị hoãn để xử lý một tác vụ

khác, sau đó được gọi lại để xử lý tiếp

Nhiều tác vụ được xử lý đồng thời (đang được xử lý)

Đa nhiệm (multitasking)

Lưu ý: Đồng thời (concurrent) khác song song (parallel).

Phù hợp khi chạy tác vụ mà không muốn chặn (block) tác vụ khác (ví dụ tác vụ chính (trình duyệt))

Nhiều Web API hiện đại là không đồng bộ, đặc biệt các thao tác I/O, request đến server, giao tiếp mạng. request 5

Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Task A Task B Task C

time

Task A

Page 6: Bài giảng Phát triển ứng dụng web - iTest

Ví dụ lập trình không đồng bộ

6

function aFunction() {

setTimeout( function() {

let ret = sFunction();

console.log(ret);

}, 0);

}

console.log("begin");

aFunction();

console.log("end");

Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

beginendHello S!

Page 7: Bài giảng Phát triển ứng dụng web - iTest

Hàm gọi lại Là cách thức truyền thống để tạo tác vụ không đồng

bộ

Hàm gọi lại (callback) được truyền vào tham số cho một hàm khác (thường là Web API)

window.setTimeout(callback, time);

window.setInterval(callback, time);

window.requestAnimationFrame(callback);

obj.addEventListener(eventName, callback);

Hàm gọi lại không được thực hiện ngay, mà được đưa vào hàng đợi và được "gọi lại" ở một thời điểm trong tương lai.

7Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 8: Bài giảng Phát triển ứng dụng web - iTest

Lập trình không đồng bộ hiện đại: promise-based

8

Browser ... 3. continue working

asyncF

1. Do me

this task

please! 4. Task done!

Check givenpromise fortask's result

5. Okie, thanksI'll make use of theresult soon.

2. Okie, this is my promise!

Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 9: Bài giảng Phát triển ứng dụng web - iTest

Promise "Giấy hẹn trả kết quả"

Chứa kết quả trả về khi hoàn thành, lỗi nếu thất bại

Được đưa vào hàng đợi và xử lý sau.

Khác hàng đợi callback

9Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 10: Bài giảng Phát triển ứng dụng web - iTest

Hàm tạo Promise()

var promiseObj = new Promise( function(fulfill, reject) {

// typically, some asynchronous operation.

} );

Hai hàm fulfill, reject tự động được tạo và buộc vào đốitượng promise

fulfill trả về kết quả nếu nhiệm vụ hoàn thành

reject trả về kết quả nếu nhiệm vụ thất bại hay bị từ chối

10Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 11: Bài giảng Phát triển ứng dụng web - iTest

Ví dụ 1

function aFunction1 () {

return new Promise(

function(fulfill, reject) { fulfill("Hello A1!");

}

);

}

11Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 12: Bài giảng Phát triển ứng dụng web - iTest

Ví dụ 2function imgLoad(url) {

return new Promise(function(fulfill, reject) {

let request = new XMLHttpRequest();

request.open('GET', url);

request.responseType = 'blob';

request.onload = function() {

if (request.status === 200) {

fulfill(request.response); } else { reject(Error("didn\'t" )); }

}

request.send();

});

}

12Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 13: Bài giảng Phát triển ứng dụng web - iTest

Tạo promise bằng async Thay cho sử dụng constructor để tạo promise

Từ khóa async được thêm vào định nghĩa hàm

Câu lệnh return của hàm sẽ tự động bao gói kết quả trả về trong promise.

Hàm luôn trả về promise

Cách viết hàm như hàm đồng bộ

async function doTaskA() { return value; };

let promiseA = doTaskA();

13Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 14: Bài giảng Phát triển ứng dụng web - iTest

Ví dụ 1function aFunction1 () {

return new Promise(

function(fulfill, reject) { fulfill("Hello A1!");

}

);

}

async function aFunction2 () {

return ("Hello A2!");

}

14Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 15: Bài giảng Phát triển ứng dụng web - iTest

Ví dụ 2

async function imgLoad2(url) { let request = new XMLHttpRequest();

request.open('GET', url);

request.responseType = 'blob';

request.onload = function() {

if (request.status === 200) {

return (request.response);

}

request.send();

}

15Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 16: Bài giảng Phát triển ứng dụng web - iTest

Các phương thức của promise Chức năng

Trả kết quả

tại một thời điểm nào đó trong tương lai

Các phương thức cho đối tượng/thể hiện

then()

catch()

finally()

Các phương thức tĩnh

all()

allSettled()

any()

race()

...16

Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 17: Bài giảng Phát triển ứng dụng web - iTest

promise.then() let promise1 = new Promise(...);

let promise2 = promise1.then(callback);

let promise3 = promise2.then(function(param) {});

hoặc viết nối

let promise3 = Promise(...).then(callback).then(function(param) {});

Nếu kết quả là thành công (fulfill) thì gọi callback và

Tự động bóc kết quả chứa trong promise và truyền vào tham số cho callback

Chuyển callback thành hàm không đồng bộ

Tạo thành chuỗi promise17

Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 18: Bài giảng Phát triển ứng dụng web - iTest

Ví dụ chuỗi promise 1

aFunction1()

.then(/* then () tự động bóc nội dung (kết quả) chứa trong promise và truyền vào tham số cho callback */

function (ret) {

console.log(ret);

}

);

18Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 19: Bài giảng Phát triển ứng dụng web - iTest

Ví dụ chuỗi promise 2imgLoad('myLittleVader.jpg')

.then( /* then () tự động bóc nội dung (kết quả) chứa trong promise và truyền vào tham số cho callback */

function(resp) {

let body = document.querySelector('body');

let myImage = document.createElement("img");

myImage.src = window.URL.createObjectURL(resp);

body.appendChild(myImage);

return myImage; /* then() tự động tạo promise mới và đưa kết quả trả về vào promise mới , trả về promise mới */

})

.then (function(newCreatedImage) { ... });

19Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 20: Bài giảng Phát triển ứng dụng web - iTest

promise.catch()

Sau tất cả các then()

Được gọi nếu ít nhất một promise (.then()) thất bại.

imgLoad('myLittleVader.jpg')

.then( function(resp) { ... })

.then (function(newCreatedImage) { ...})

.catch (function(err) { console.log(err); });

20Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 21: Bài giảng Phát triển ứng dụng web - iTest

promise.finally() Cuối chuỗi promise

Được thực hiện sau cùng bất luận chuỗi promise hoàn thành tất cả hay có một promise thất bại

imgLoad('myLittleVader.jpg')

.then( function(resp) { ... })

.then (function(newCreatedImage) { ...})

.catch (function(err) { console.log(err); })

.finally(function() { console.log("finished"); });

21Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 22: Bài giảng Phát triển ứng dụng web - iTest

Lập trình không đồng bộ === Lập lịch/kế hoạch

doTaskA() // promiseA queued

.then (doTaskB) // promiseA fulfilled, promiseB queued

.then(doTaskC) // promiseB fulfilled, promiseC queued

...

.catch(handleError) // at least one promise was rejected

.finally(finish); // away do last

22Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 23: Bài giảng Phát triển ứng dụng web - iTest

Promise.all() Khi tất cả các promise hoàn thành hoặc ít nhất một

promise thất bại

let promiseA = doTaskA() ;

let promiseB = doTaskB() ;

let promiseC = doTaskC() ;

let promiseD = Promise.all([promiseA , promiseB, promiseC]);

promiseD.then(function(arr) {...});

23Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 24: Bài giảng Phát triển ứng dụng web - iTest

Promise.allSettled() Khi tất cả các promise được giải quyết xong (hoặc

hoàn thành hoặc thất bại)

let promiseA = doTaskA() ;

let promiseB = doTaskB() ;

let promiseC = doTaskC() ;

let promiseD = Promise.allSettled([promiseA , promiseB, promiseC]);

promiseD.then(function(arr) {...});

24Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 25: Bài giảng Phát triển ứng dụng web - iTest

Promise.any() Khi có ít nhất một promise hoàn thành

let promiseA = doTaskA() ;

let promiseB = doTaskB() ;

let promiseC = doTaskC() ;

let promiseD = Promise.any([promiseA , promiseB, promiseC]);

promiseD.then(function(value) {...});

Có thể không có promise nào hoàn thành (tất cả đềuthất bại)

25Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 26: Bài giảng Phát triển ứng dụng web - iTest

Promise.race() Khi có ít nhất một promise hoàn thành hoặc thất bại

let promiseA = doTaskA() ;

let promiseB = doTaskB() ;

let promiseC = doTaskC() ;

let promiseD = Promise.race([promiseA , promiseB, promiseC]);

promiseD.then(function(value) {...});

26Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 27: Bài giảng Phát triển ứng dụng web - iTest

await Đợi một promise cho đến khi promise được hoàn thành hoặc

thất bại let ret= await aFunction().catch((err) => { console.error(err); });

Chỉ được dùng await trong hàm async

27Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 28: Bài giảng Phát triển ứng dụng web - iTest

await Thay cho then

async function fetchAndDecode(url, type) {

fetch(url).then(function(response) {

if (!response.ok) {

throw new Error(`HTTP error! status: ${response.status}`);

} else {

if (type === 'blob') {

response.blob().then(function(content) {

return content;

});

} else if (type === 'text') {

response.text().then(content => {return content;});

}

}

});

}28

Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 29: Bài giảng Phát triển ứng dụng web - iTest

Hàng đợi microtask Promise được đưa vào hàng đợi microtask

(microtask/job queue).

Tất cả promise trong hàng đợi, kể cả promise mới phát sinh khi xử lý promise cũ, sẽ được xử lý ngay khi một task kết thúc và trước khi task khác được xử lý.

29Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 30: Bài giảng Phát triển ứng dụng web - iTest

Browser’s JavaScript runtime

30Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Macrotask queue

Microtask queuepromise 1 promise 2

Page 31: Bài giảng Phát triển ứng dụng web - iTest

Hàng đợi macrotask

Trình duyệt/JavaScript hoạt động theo sự kiện (event-driven)

Thực thi chỉ xảy ra khi có sự kiện (nhằm xử lý sự kiện đó)

run script, load, readystatechange, click, mouseover, timeout, ...

Các hàm xử lý sự kiện (event handler, callback) đượcđưa vào hàng đợi macrotask (task/message/callback queue).

31Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 32: Bài giảng Phát triển ứng dụng web - iTest

Vòng lặp sự kiện (Event loop)while (true) {

if (the call stack is empty) {

while (the microtask queue is not empty) {

dequeue the oldest (micro)task and run it (push it to the call stack)

}

if (the macrotask queue is not empty) {

dequeue the oldest (macro)task and run it (push it to the call stack)

}

repaint (DOMchanged)

}

}32

Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 33: Bài giảng Phát triển ứng dụng web - iTest

Ví dụconsole.log('Start');

setTimeout(() => { console.log('setTimeout 1'); }, 10);

setTimeout(() => { console.log('setTimeout 2'); }, 0);

new Promise(function(fulfill, reject) { fulfill('Promise 1'); })

.then (function(res) {console.log(res); return "Sub Promise 1";})

.then (function(res) {console.log(res);});

new Promise((fulfill, reject) => { fulfill('Promise 2'); })

.then (res => {console.log(res); return "Sub Promise 2";})

.then (res => {console.log(res);});

console.log('End');33

Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 34: Bài giảng Phát triển ứng dụng web - iTest

Thêm về microtask promise là một dạng microtask

Mỗi khi được tạo, promise được đưa vào hàng đợimicrotask

Có thể tạo và thêm một microtask vào hàng đợimicrotask bằng hàm queueMicrotask(function(){});

34Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 35: Bài giảng Phát triển ứng dụng web - iTest

Lời khuyên Sử dụng promise/hàm không đồng bộ để tránh block

luồng chính với các thao tác

Vào/ra

Gửi request/nhận response

Giao tiếp mạng

Không sử dụng promise/hàm không đồng bộ với các thao tác

Chỉ xử lý trong CPU

Vì chỉ có tác dụng thay đổi thứ tự thực hiện các job và task

Vẫn block tác vụ tiếp theo

35Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 36: Bài giảng Phát triển ứng dụng web - iTest

Xử lý song song

36Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 37: Bài giảng Phát triển ứng dụng web - iTest

JavaScript đơn luồng Đơn luồng (single-threaded)

Dù có nhiều CPU hoặc CPU có nhiều core, các tác vụ JavaScript cũng chỉ được xử lý trên một luồng (main thread)

Các tác vụ được thực thi một cách tuần tự (sequentially)

Giải pháp cho xử lý đa luồng trong môi trường thực thi của trình duyệt

Web worker

chạy ở luồng khác

tận dụng được CPU và CPU core khác

chạy các tác vụ lớn

luồng chính/trình duyệt) không bị block

37Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 38: Bài giảng Phát triển ứng dụng web - iTest

Web worker Cho phép chạy tệp JavaScript ở luồng (thread) riêng ở

chế độ nền bên ngoài luồng chính (ngữ cảnh window)

Không làm cho luồng chính bị treo (non-blocking)

Giao tiếp với luồng chính bằng gửi/nhận thông báo (message)

Gửi: postMessage(m);

Nhận: onmessage = function() {}

Có thể mã bất kỳ, ngoại trừ

không truy cập được DOM

không sử dụng được một số phương thức và thuộc tính của window

Functions and classes available to Web Workers

38Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 39: Bài giảng Phát triển ứng dụng web - iTest

Phân loại web worker Chuyên biệt (dedicated web worker )

chỉ làm việc được với một luồng chính (window)

Chia sẻ (shared web worker )

có thể làm việc (chia sẻ) được với nhiều luồng chính (window, tab, iframe)

cùng domain

39Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 40: Bài giảng Phát triển ứng dụng web - iTest

Dedicated web workers

40Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 41: Bài giảng Phát triển ứng dụng web - iTest

Trang chính

41Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 42: Bài giảng Phát triển ứng dụng web - iTest

Shared web worker

42Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 43: Bài giảng Phát triển ứng dụng web - iTest

Trang chính

43Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 44: Bài giảng Phát triển ứng dụng web - iTest

Web API

44Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 45: Bài giảng Phát triển ứng dụng web - iTest

Browser’s JavaScript runtime

45Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Macrotask queue

Microtask queuepromise 1 promise 2

Page 46: Bài giảng Phát triển ứng dụng web - iTest

46Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 47: Bài giảng Phát triển ứng dụng web - iTest

Một số API quan trọng DOM

Fetch

URL

...

47Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 48: Bài giảng Phát triển ứng dụng web - iTest

Fetch API Cung cấp giao diện cho phép

tạo và gửi request

nhận response

tạo response

Các đối tượng

Request

Response

Headers

Body (mixin)

Phương thức toàn cục

fetch()

bản thay thế hiện đại hơn XmlHttpRequest (AJAX)48

Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 49: Bài giảng Phát triển ứng dụng web - iTest

fetch() Đơn giản với GET method

49Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 50: Bài giảng Phát triển ứng dụng web - iTest

fetch() Cấu hình header và body của HTTP request

50Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 51: Bài giảng Phát triển ứng dụng web - iTest

fetch() POST dữ liệu JSON

51Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 52: Bài giảng Phát triển ứng dụng web - iTest

fetch() Upload file (form)

52Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 53: Bài giảng Phát triển ứng dụng web - iTest

Headers và Request Tạo đối tượng Request rồi gửi

Ít dùng

53Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 54: Bài giảng Phát triển ứng dụng web - iTest

Response Thuộc tính

Response.status

Response.statusText

Response.ok

...

Phương thức

Response.arrayBuffer()

Response.blob()

Response.json();

Response.text();

...

54Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.

Page 55: Bài giảng Phát triển ứng dụng web - iTest

Tiếp theo

PWA

55Lê Đình Thanh, Bài giảng Phát triển ứng dụng web.