Trong lập trình ứng dụng hẳn là ai cũng phải đau đầu với vấn đề Blocking hay Non Blocking. Sẽ có nhiều lúc bạn chả hiểu vì sao chương trình của mình lại chạy không như ý muốn, khi thì câu lệnh này chạy trước, khi thì câu lệnh kia lại chạy trước (và nó thường gặp khi bạn dính phải cơ chế bất đồng bộ - non blocking): Blocking tức đồng bộ:

  • Để hiểu một cách đơn giản về Blocking thì chúng ta có thể liên tưởng đến hình ảnh xếp hàng thời bao cấp, từng người lần lượt từ trước đến sau sẽ đi lên sử dụng tem phiếu. Vậy trong code sẽ như thế nào? Tất nhiên các dòng lệnh sẽ được chạy lần lượt từ trên xuống dưới 1 cách chờ đợi nhau, khi dòng trên kết thúc thì dòng tiếp theo mới được phép bắt đầu thực hiện. Việc đó đúng ngay cả khi ta sử dụng 2 câu lệnh gọi 2 hàm khác nhau. Chúng sẽ thực hiện lần lượt kết thúc functions 1 rồi đến functions 2.

  • 1 Ví dụ trên Javascript:

function a(){
	//do something blocking.
}

function b(){
	//do something blocking.
}

function main(){
	//blocking code, call function a() end to call function b().
	a();
	b();
}

Non Blocking tức bất đồng bộ:

  • Nếu ai đó đã tiếp xúc với khái niệm Thread(Luồng) và Multi Thread (Đa luồng) hay xử lý đa luồng trong lập trình ứng dụng thì cũng sẽ hiểu Non Blocking nó sẽ gần giống như thế. Tức là với đa luồng ta có thể cho 2 luồng chạy song song nhau, có hoặc không liên quan đến giá trị biến chung của nhau đang chiếm giữ. Và Non blocking cũng giống như đoạn code đang chạy blocking bỗng mở một luồng chạy riêng ra và xử lý song song vs các đoạn code sau mà ko bắt chúng chờ đợi. Đó chính là nguyên nhân tại sao mà đôi khi các bạn sẽ gặp những vấn đề rằng giá trị không như mong muốn. và điển hình mình sẽ ví dụ Non blocking và sự thay đổi giá trị của nó ntn trên JS + Ajax (Jquery) - Lý do vì sao mình chọn Ajax vs Jquery vì nó sẽ cho chúng ta thấy dễ nhất và hầu như các bạn sử dụng Ajax của Jquery đều từng phải đau đầu vì chả hiểu sao biến của mình nó mất tiêu, hay cũng như timeout của nó đủ để chúng ta nhìn ngay thấy sự thay đổi:
var global_tmp = 0;
$.ajax({
	url: 'http://sample.demo/api',
	success: function(data){
		for(var i=0; i<100; i++){
			global_tmp = i;
		}
		console.log('SUCCESS', global_tmp);
	},
	error: function(err){
		for(var i=0; i<100; i++){
			global_tmp = i;
		}
		console.log('ERR', global_tmp);
	}
});

console.log('END', global_tmp);

Nếu xét theo phương diện blocking. Thì chúng ta sẽ show ra END cuối cùng và lúc này biến global_tmp đã thay đổi dù ajax có get được hay không. và blocking thì giá trị của chúng ta sẽ là 100

Tuy nhiên. với mặc định Ajax trong Jquery sẽ là Non-blocking hay khái niệm Asynctask. và chúng ta sẽ nhận việc in ra màn hình END vs global_tmp không phải giá trị như ta nghĩ - Lý do là Task làm việc thay đổi giá trị của biến đang được tách thành luồng khác và chạy song song với các dòng lệnh tiếp theo.

Bonus: xử lý thế nào để không bị như vậy?

  • Thứ nhất các bạn có thể tìm hiểu về khái niệm Callback trong JS và tất nhiên sử dụng biến trong hàm callback chứ ko đặt ngoài như vậy
  • Và còn nữa, jquery hỗ trợ bạn gọi với cơ chế blocking bằng cách đưa thêm 1 params vào cho nó là: {async: false}
var global_tmp = 0;
$.ajax({
	url: 'http://sample.demo/api',
	async: false,
	success: function(data){
		for(var i=0; i<100; i++){
			global_tmp = i;
		}
		console.log('SUCCESS', global_tmp);
	},
	error: function(err){
		for(var i=0; i<100; i++){
			global_tmp = i;
		}
		console.log('ERR', global_tmp);
	}
});

console.log('END', global_tmp); 

:) Và khi đó bạn thoải mái gọi ở dòng lệnh bên dưới như thế này 1 cách bình thường.


Tan Bui

Developer all platform