Tìm hiểu về Synchronous và Asynchronous trong JavaScript

Cập nhật: Lượt xem: 677 [ Javascript ]

Tìm hiểu về Synchronous và Asynchronous trong JavaScript

Tìm hiểu về Synchronous và Asynchronous trong JavaScript

Một request kỳ quặc

Quay trở lại với câu chuyện về Mr X và bộ phim mà bạn tới xem. Trước khi đi bạn để lại một công việc cho Mr X và bảo với anh ấy chỉ được bắt đầu công việc sau năm tiếng kể từ khi anh ấy anh nhận được tin nhắn của bạn.

Anh ấy thì không vui với chuyện đó, hãy nhớ rằng, anh ấy không nhận tin nhắn mới cho tới khi anh ấy giải quyết xong công việc hiện tại và nếu anh ấy nhận tin nhắn đó, anh ấy sẽ  thực hiện khi hoàn thành xong công việc cộng với năm tiếng mới bắt đầu làm việc. Đó là một sự lãng phí thời gian, anh ấy cần nhận được sự giúp đỡ, đó là Mr H.

Thay vì chờ đợi, Mr X yêu cầu Mr H để các tin nhắn mới vào hộp chờ sau thời gian trôi qua thì chuyển sang tin nhắn kế tiếp.

Sau khi năm giờ trôi qua, Mr H cập nhật hàng đợi với một tin nhắn mới. Sau khi hoàn thành công việc trước Mr H, Mr X sẽ thực hiện tiếp yêu cầu mà bạn để lại. Vì vậy, theo cách này, bạn có thể để lại thời gian bắt đầu công việc mà không cần phải tốn thời gian trong lúc Mr X xử lý công việc.

Nhưng có câu hỏi rằng tại sao Mr H lại để tin nhắn trong hàng chờ mà không trực tiếp liên hệ với Mr X ? Bởi vì như mình đã đề cập ở phần 1, cách duy nhất để liên lạc với Mr X đó là nhắn tin bằng điện thoại – không có ngoại lệ nhé.

1. Phương thức setTimeout()

Giả sử bạn có một đoạn code mà bạn muốn thực hiện sau một khoảng thời gian nhất định. Để làm được điều đó, bạn chỉ cần để nó vào trong một function sau đó thêm phương thức setTimeout() với thời gian bạn muốn. Cú pháp setTimeout() như sau:

setTimeout(function, delay-time, arg...)

arg… là tham số đại diện cho số chức năng có và delay-time được thêm dưới đơn vị milliseconds. Dưới đây là một ví dụ code đơn giản cho ra kết quả “hey” trong giao diện sau ba giây.

setTimeout( function() { console.log('hey') }, 3000 );

Khi setTimeout() bắt đầu chạy thay vì chặn các tin nhắn cho đến khi thời gian chờ kết thúc và khi thời gian được kích hoạt, thì các stack được xử lý dần để có chỗ trống cho tin nhắn tiếp theo (tương tự nhưng câu chuyện về Mr X và Mr H).

Khi thời gian chờ kết thúc, thông báo mới sẽ được thêm vào hàng chờ, vòng lập xảy ra tin nhắn được chuyển vào. Và vì thế mà nó xử lý các thông tin sẽ không được đồng bộ.

js-re-timer-300x142

2. AJAX

AJAX (Asynchronous JavaScript and XML) là sử dụng XMLHttpRequest (XHR) API để thực hiện yêu cầu của máy chủxử lý các câu trả lời.

Khi trình duyệt chạy requests mà không cần XMLHttpRequest, trang sẽ refreshestải lại lại UI. Nhưng khi xử lý các request và đáp ứng được responses bởi XHR API thì UI sễ không bị thay đổi.

xhr-300x142

Vì vậy, mục đích chủ yếu là thực hiện các request mà không phải reload trang. Bây giờ, khi mà “asynchronous” trong việc này ? Thì chỉ cần sử dụng XHR code (cái mà lát nữa ta sẽ thấy) nó không có nghĩa là AJAX, bởi vì XHR API có thể làm được hai cách “synchronous” và “asynchronous”.

Nếu HXR được chỉnh để đồng bộ (synchronous), khi đó các function sẽ chờ đợi cho đến khi nhận được phản hồi và xử lý trước khi lặp lại.

Code Example 1

Ví dụ này về XMLHttpRequest gồm method open(), validates yêu cầu URL và method send() để gửi yêu cầu.

Asynchronous XHR

1 var xhr = new XMLHttpRequest();
2 xhr.open("GET", url);
3 xhr.send();

Bất kỳ response truy cập trực tiếp dữ liệu sau send() đều là vô ích, bởi vì send() sẽ không chờ cho đến khi request hoàn thành. Nên nhớ rằng, XMLHttpRequest được thiết lập mặc định là “asynchronously”.

Code Example 2

Các file hello.txt trong ví dụ này là file text đơn giản chứa text “hello”. Response cho ra của XHR là không hợp lệ vì nó không cho ra text “hello”.

Asynchronous XHR

1 var xhr = new XMLHttpRequest();
2 xhr.open("GET", "hello.txt");
3 xhr.send();
4 document.write(xhr.response);
5 // empty string

XHR luôn thực hiện công việc kiểm tra response mỗi mili giây và khởi tạo events bổ sung cho từng resquest của các states khác nhau khi chạy. Khi response đã được load, load event được khởi tạo bởi XHR, mới có thể cho ra response hợp lệ.

Asynchronous XHR

1 var xhr = new XMLHttpRequest();
2 xhr.open("GET", "hello.txt");
3 xhr.send();
4 xhr.onload = function(){ document.write(this.response) }
5 // writes 'hello' to the document

Response bên trong load event sẽ cho ra outputs chính xác “hello”.

Làm theo cách “asynchronous” được ưa chuộng hơn, vì nó không block các script cho đến khi request hoàn thành.

Nếu response đã được xử lý theo cách “synchronously”. Chúng ta sẽ bỏ qua sai sót của đối số trong open(), mà các flag của XHR API báo rằng nó cần được “synchronous”(theo mặc định thì đối số cuối cùng của open() là đúng mà bạn không cần phải xác định).

Synchronous XHR

1 var xhr = new XMLHttpRequest();
2 xhr.open("GET", "hello.txt", false);
3 xhr.send();
4 document.write(xhr.response);
5 // writes 'hello' to document

Tại sao ta cần học những điều này ?

Hầu như những người mới bắt đầu làm quen đều mắc các sai lầm về việc “asynchronous” như là setTimeout() và AJAX, ví dụ bằng cách đưa ra setTimeout() để thực hiện các đoạn code sau một khoảng thời gian hoặc cách xử lý response trực tiếp trong hàm AJAX resquest.

Nếu bạn biết cách sử dụng chúng một cách phù hợp thì bạn có thể tránh được sự nhầm lẫn như thế. Bạn nên biết rằng lệnh setTimeout() sẽ không thực thi đoạn mã khi hết thời gian, nhưng khi thời gian trong setTimeout() hết thì yêu cầu thực hiện lệnh sẽ được đưa vào hàng chờ và có một tin nhắn sẽ gửi tới bạn. Chỉ cần gọi lệnh lên thì hàm sẽ được thực thi ngay.