Bài viết
Xử lí không đồng bộ trong javascript
Xứ lí không đồng bộ (async) là 1 phần quan trọng trong javascript. Cách tiếp cận phổ biến với xử lí không đồng bộ là sử dụng các callback. Khác với việc thực hiện tuần tự các phép toán như trong 1 vòng for, có 1 khoảng thời gian chênh lệch nhất định giữa thời điểm giữa phần chương trình được chạy ngay lập tức và phần chương trình khác được gọi ra sau đó (callback).
Ví dụ như 1 lệnh ajax gửi request lên server và sau khi nhận được thành công data
trả về từ server thì phần chương trình trong callback sẽ được thực hiện. Thời điểm mà callback được thực hiện không phải là ngay lập tức sau khi có request ajax mà có thể là 1 vài giây sau đó tùy thuộc vào tốc độ xử lí của server. Nếu coi thời điểm bắt đầu gọi là now thì thời điểm callback được thực hiện là 1 mốc thời gian later nào đấy và có 1 sự chênh lệch (gap) giữa now và later. Để hiểu rõ hơn cách mà javascript xử lí không đồng bộ như thế nào, chúng ta hãy chia nhỏ chương trình thành những phần nhỏ và xem xét cách chúng vận hành.
A Program in Chunks
Chúng ta chia chương trình javascript thành các đoạn (chunk) theo thời điểm mà chúng
được thực thì (now or later). Một trong những vấn đề thường gặp của những người mới
lập trình với javascript là cảm giác phần later sẽ chạy ngay lập tức sau now và do đó
bỏ qua các khối kiểm tra cần thiết.
1
2
3
4
|
var data = ajax ( "http://some.url" ) ;
console . log ( data ) ;
|
Khi nhìn qua đoạn code trên thì do thói quen nhiều người không để ý rằng kết quả data được trả về nằm trong phần xử lí không đồng bộ nên khả năng rất lớn là lệnh log lại giá trị của data được thực thi trước khi có data trả về từ câu lệnh ajax. Chúng ta gọi câu lệnh ajax tại thời điểm now nhưng kết quả data trả về là 1 thời điểm later. Giải pháp đơn giản cho vấn đề này là đặt câu lệnh log vào trong callback khi request ajax hoàn thành.
1
2
3
4
5
|
ajax ( "http://some.url" , function callbackFunction ( data ) {
console . log ( data ) ;
} ) ;
|
Async Console
console.log là lệnh rất hay được sử dụng đặc biệt là trong trường hợp dùng để debug. Tuy nhiên trên thực tế trên 1 vài trình duyệt và trong 1 số điều kiện, lệnh console.log không đưa ra kết quả output ngay lập tức. Ví dụ như khi I/O quá chậm lệnh console này có thể chạy không đồng bộ và chúng ta không biết chính xác thời điểm lệnh này được thực thi là khi nào.
1
2
3
4
5
6
7
8
|
var a = {
index : 1
} ;
console . log ( a ) ;
a . index ++ ;
|
Trong trường hợp này sẽ có lúc kết quả output của console.log không phải là 1 mà có thể là 2.
Event Loop
Javascript không chạy độc lập mà chạy trong 1 hosting enviroment, thường thì là trình duyệt. Hiện nay Javascript cũng có thể hoạt động trong môi trường server (Node.js). Khi Javascript xử lí các đoạn code của chương trình, có 1 cơ chế được sử dụng đó là event loop. Ví dụ khi chương trình javscript chạy 1 request ajax để lấy data từ server và sau đó thực hiện 1 callback trong phần response trả về, JS engine sẽ nói với hosting environment sẽ trì hoãn việc thực thi callback ngay lập tức mà hãy gọi nó khi hoàn thành xong công việc lấy data từ server. Vậy event loop là gì. Hãy xem xét đoạn code mô phỏng dưới đây.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
var eventLoop = [ ] ;
var event ;
while ( true ) {
if ( eventLoop . length > 0 ) {
event = eventLoop . shift ( ) ;
try {
event ( ) ;
}
catch ( err ) {
reportError ( err ) ;
}
}
}
|
Vòng while vô hạn sẽ được thực hiện. Ở đây ta có thể hiểu event loop như 1 queue. Tại mỗi lần lặp lại trong vòng while thì queue này được check xem có event nào trong đó hay không, nếu có thì lấy event đó ra khỏi queue và thực thi nó. Khi chạy lệnh setTimeout thì cho callback trong lệnh này sẽ được cho vào event loop và nếu như trong event loop đang có các callback khác thì callback của setTimeout sẽ phải chờ này tới lượt. Điều đó có nghĩa là nếu bạn set interval cho lệnh setTimeout là 1s thì không có nghĩa là sau 1s callback của nó sẽ được gọi mà chúng ta sẽ chỉ có thể đảm bảo là callback đó sẽ không được chạy khi chưa quá 1s
Parallel Threading
Chúng ta khá dễ nhầm lẫn giữa 2 khái niệm async (không đồng bộ) và parallel (song song). Xử lí không đồng bộ ám chỉ về việc chênh lệch thời gian giữa now và later trong khi xử lí song song thì xảy ra cùng lúc. Những công cụ để xử lí song song là process và thread. Trong event loop các task được xử lí tuần tự và không cho phép truy cập song song. Khi xử lí song song, việc thực thi xen kẽ giữa các thread xảy ra ở level thấp.
1
2
3
4
5
6
|
function later ( ) {
answer = answer * 2 ;
console . log ( "Answer:" , answer ) ;
}
|
Ví dụ lệnh answer = answer * 2 thực ra bao gồm các bước load giá trị hiện tại của answer, thực hiện tính toán rồi sau đó mới lưu giá trị mới vào answer
Việc xử lí song song có thể gây ra các ảnh hưởng không ngờ đến.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
var a = 20 ;
function foo ( ) {
a = a + 1 ;
}
function bar ( ) {
a = a * 2 ;
}
ajax ( "http://some.url.1" , foo ) ;
ajax ( "http://some.url.2" , bar ) ;
|
Trong Javascript khi xử lí single-thread thì giá trị a trả về sau khi thực hiện 2 callback foo, bar sẽ là 42 hoặc 41 tùy thuộc xem callback nào được gọi trước. Bây giờ nếu như Javascript thực hiện xử lí song song hãy xem có vấn đề gì xảy ra. Trước hết chúng ta chia nhỏ các công việc được thực hiện trong foo và bar Gọi X và Y là các địa chỉ vùng nhớ tạm thời.
1
2
3
4
5
6
7
|
foo ( ) :
1a. load giá trị củ a a tạ i X
1b. lư u 1 và o Y
1c. cộ ng X và Y , rồ i lư u kế t quả và o X
1d. lư u giá trị tạ i X cho a
|
1
2
3
4
5
6
7
|
bar ( ) :
2a. load giá trị củ a a tạ i X
2b. lư u 1 và o Y
2c. nhâ n X và Y , rồ i lư u kế t quả và o X
2d. lư u giá trị tạ i X cho a
|
Khi xử lí song song nếu quá trình thực thi như sau thì kết quả trả về sẽ là 44:
1a 2a 1b 2b 1c 1d 2c 2d
và nếu thứ tự thực hiện khác đi chúng ta lại có 1 kết quả khác
1a 2a 2b 1b 2c 1c 1d 2d
kết quả sẽ là 21
Có thể thấy xử lí song song với thread là khá phức tạp khi mà kết quả trả về là rất khác nhau tùy theo thứ tự thực hiện các phép toán. Mặc dù khi xử lí single thread kết quả trả về vẫn là không đồng nhất tuy nhiên nó nằm ở mức function (event) order tức là kết quả chỉ phụ thuộc vào thứ tự xảy ra của event chứ không đến mức statement level.
Noninteracting
Khi thực hiện xử lí không đồng bộ nếu chúng ta đảm bảo việc các callback thực hiện các công việc riêng rẽ, độc lập, không có tương tác gì với nhau thì cho dù thứ tự thực thi của các callback có khác nhau đi chăng nữa cũng không ảnh hưởng gì đến kết quả.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
var res = { } ;
function foo ( results ) {
res . foo = results ;
}
function bar ( results ) {
res . bar = results ;
}
ajax ( "http://some.url.1" , foo ) ;
ajax ( "http://some.url.2" , bar ) ;
|
Trong trường hợp này thì cho dù foo hay bar chạy trước thì cũng không ảnh hưởng gì đến kết quả ?
Interaction
Việc đảm bảo các callback thực hiện các công việc riêng rẽ, độc lập sẽ giúp chương trình chạy ổn định nhưng trên thực tế nhiều lúc chúng ta phải xử lí các callback có tinh tương tác với nhau (ví dụ như cùng thay đổi kết cấu DOM chẳng hạn). Việc các callback này cùng chia sẻ 1 tài nguyên nào đó (1 biến global chẳng hạn) có thể làm chương trình bị xử lí sai.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
var a , b ;
function foo ( x ) {
a = x * 2 ;
baz ( ) ;
}
function bar ( y ) {
b = y * 2 ;
baz ( ) ;
}
function baz ( ) {
console . log ( a + b ) ;
}
ajax ( "http://some.url.1" , foo ) ;
ajax ( "http://some.url.2" , bar ) ;
|
Trong ví dụ này khả năng cao là function baz sẽ được gọi quá sớm khi mà 1 trong 2 function bar hoặc foo chưa hoàn thành dẫn đến 1 trong 2 biến a hoặc b bị undefined. Cách khắc phục vấn đề này là thêm các block check điều kiện.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
var a , b ;
function foo ( x ) {
a = x * 2 ;
if ( a && b ) {
baz ( ) ;
}
}
function bar ( y ) {
b = y * 2 ;
if ( a && b ) {
baz ( ) ;
}
}
function baz ( ) {
console . log ( a + b ) ;
}
ajax ( "http://some.url.1" , foo ) ;
ajax ( "http://some.url.2" , bar ) ;
|
Với cách xử lí như vậy, chúng ta sẽ đảm bảo chỉ thực hiện baz khi cả 2 biến a và b đều đã nhận được giá trị
Kết luận
- Javascript chia chương trình thành các đoạn code, có phần sẽ chạy ngay lập tức (now) có phẫn sẽ chạy vào 1 thời điểm khác sau đó.
- Javascript sử dụng event loop để quản lí các event, bản chất là 1 queue và sẽ thực hiện lần lượt cho đến hết các event trong queue đó.
- Việc đảm bảo các event hoạt động riêng rẽ độc lập sẽ giúp kết quả trả về không bị phụ thuộc vào thứ tự thực hiện của các event.
- Khi nhiều event cùng chia sẻ 1 tài nguyên nào đó cần có các cơ chế kiểm tra để đảm bảo kết quả trả về chính xác
- Thực hiện nhiều hàm đồng thời trong Java
- "Kết đôi" online & offline - Xu hướng mới của các nhà bán lẻ
- Rút tiền từ ATM bằng điện thoại thông minh
- Chính sách thuế giá trị gia tăng (GTGT) đối với phần mềm và dịch vụ phần mềm
- Khôi phục cài đặt iPhone bằng phím cứng
- Kiến trúc của hệ điều hành Android như thế nào?
- Single-thread liệu đã lỗi thời?
- Kỹ thuật quay phim trên smartphone bạn nên biết
- Hướng dẫn lập trình nhận dạng hình ảnh với Opencv
- 6 Tip để trở thành lập trình viên giỏi
- Báo cho Facebook các nội dung xấu, nội dung sex...
- Hướng dẫn quản trị Magento, admin Magento user guide
DVMS chuyên:
- Tư vấn, xây dựng, chuyển giao công nghệ Blockchain, mạng xã hội,...
- Tư vấn ứng dụng cho smartphone và máy tính bảng, tư vấn ứng dụng vận tải thông minh, thực tế ảo, game mobile,...
- Tư vấn các hệ thống theo mô hình kinh tế chia sẻ như Uber, Grab, ứng dụng giúp việc,...
- Xây dựng các giải pháp quản lý vận tải, quản lý xe công vụ, quản lý xe doanh nghiệp, phần mềm và ứng dụng logistics, kho vận, vé xe điện tử,...
- Tư vấn và xây dựng mạng xã hội, tư vấn giải pháp CNTT cho doanh nghiệp, startup,...
Vì sao chọn DVMS?
- DVMS nắm vững nhiều công nghệ phần mềm, mạng và viễn thông. Như Payment gateway, SMS gateway, GIS, VOIP, iOS, Android, Blackberry, Windows Phone, cloud computing,…
- DVMS có kinh nghiệm triển khai các hệ thống trên các nền tảng điện toán đám mây nổi tiếng như Google, Amazon, Microsoft,…
- DVMS có kinh nghiệm thực tế tư vấn, xây dựng, triển khai, chuyển giao, gia công các giải pháp phần mềm cho khách hàng Việt Nam, USA, Singapore, Germany, France, các tập đoàn của nước ngoài tại Việt Nam,…
Quý khách xem Hồ sơ năng lực của DVMS tại đây >>
Quý khách gửi yêu cầu tư vấn và báo giá tại đây >>