Đồng bộ và Bất đồng bộ (Synchronous – Asynchronous) là 2 khái niệm gây khó khăn cho người mới tiếp cận Javascript (Trong đó có cả mình hồi 6 tháng trước 😁). Hiểu nôm na Đồng bộ là code chạy có tuần tự từ trên xuống dưới – từ trái qua phải, còn Bất đồng bộ thì không! Bài viết này mình tập trung giải quyết vấn đề Bất đồng bộ vì nó gây khó khăn trong quá trình phát triển.
Đầu tiên chúng ta đi đến ví dụ sau để có cái nhìn khác biệt giữa Đồng bộ và Bất đồng bộ:
1 2 3 4 5 |
let log1 = 'Gâu Gâu'; let log2 = 'Meo Meo'; console.log(log1); console.log(log2); |
Kết quả log ra “Gâu Gâu” rồi đến “Meo Meo”. Tiếp đến ví dụ sau:
1 2 3 4 5 6 7 8 |
let log1 = 'Gâu Gâu'; let log2 = 'Meo Meo'; setTimeout(function() { console.log(log1); }, 1000); console.log(log2); |
Kết quả log ra “Meo Meo” rồi đến “Gâu Gâu”. Trông 2 ví dụ trên vẫn chưa có điều bất thường xảy ra. Ok vậy chúng ta qua ví dụ tiếp.
1 2 3 4 5 6 7 8 |
let log1 = 'Gâu Gâu'; let log2 = 'Meo Meo'; setTimeout(function() { console.log(log1); }, 0); console.log(log2); |
Quái nhỉ, rõ ràng đã setTimeout giá trị là 0 mà vẫn log ra “Meo Meo” trước 🤔
Giải thích ví dụ trên: hàm setTimeout là một hàm Bất đồng bộ trong Javascript – chạy không tuần tự và bị cho vào hàng chờ, đợi cho các đoạn code tuần tự chạy xong thì nó mới được chạy tiếp (Nên Meo Meo mới được log ra trước ở ví dụ trên).
Không chỉ hàm setTimeout mà khi ta sử dụng Ajax tương tác với API cũng là một dạng Bất đồng bộ vì nó mất 1 thời gian nhất định để có thể tương tác.
Trước lúc ES6 ra đời thì các lập trình viên phải sử dụng callback để xử lý Bất đồng bộ thành Đồng bộ và kết quả nó như này…
Thôi code như này về quê chăn vịt chăn bò cho lành 😂. May thay ES6 ra đời và cho chúng ta có thêm khái niệm về Promise. Hãy thử nó qua ví dụ sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
let log1 = 'Gâu Gâu'; let log2 = 'Meo Meo'; const promise = new Promise(function(resolve, reject) { setTimeout(function() { resolve(log1); }, 1000); } ); promise.then(function(log1) {; console.log(log1); console.log(log2); }); |
Promise là một đối tượng đặc biệt dùng cho các xử lý bất đồng bộ. Nó đại diện cho một xử lý bất đồng bộ và chứa kết quả cũng như các lỗi xảy ra từ xử lý bất đồng bộ đó.
Cú pháp của Promise có dạng như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
// Có thể khởi tạo và gán nó vào một hằng, biến const promise = new Promise(function(resolve, reject) { // Nếu kết quả không gặp lỗi if (true) { // có thể truyền thêm tham số vào đây để lấy ra resolve(); } // Nếu gặp lỗi if (false) { // có thể truyền thêm tham số vào đây để lấy ra reject(); } } ); promise .then(function(resolve) {; // Nếu thành công xử lý code ở đây console.log(resolve); }) .catch(function(error) { // Nếu gặp lỗi xử lý lỗi ở đây console.log(error) }); |
Bây giờ chúng ta sẽ đến với một ví dụ thực tế (ở đây mình có sử dụng NodeJS để test API)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
const request = require('request'); // Có thể khởi tạo và gán nó vào một hằng, biến const promise = new Promise(function(resolve, reject) { request( 'http://5c43e48357499f00143cedd1.mockapi.io/api/users', function (error, response, body) { let info = {}; if (error) { return reject(error); } if (response.statusCode == 200) { info = JSON.parse(body); return resolve(info); } }); } ); promise .then(function(resolve) {; // Nếu thành công xử lý code ở đây console.log(resolve); }) .catch(function(error) { // Nếu gặp lỗi xử lý lỗi ở đây console.log(error) }); |
Các bạn có thể kiểm tra kết quả trên ở đây: https://repl.it/@chungnq/Promise-basic-example
Ủa vậy trông nó khác gì callback ???
Khi mới tìm hiểu mình cũng đặt ra câu hỏi tương tự, nhưng đi sâu vào phân tích thì nó có 2 ưu điểm sau:
1. Hỗ trợ Chaining
2. Hỗ trợ bắt lỗi tốt hơn.
1. Promise hỗ trợ Chaining
Khi lồng nhiều điều kiện Bất đồng bộ với nhau thì cú pháp nó sẽ như này:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// Dùng callback hell con_chó_gặp_con_mèo(function(sủa) { con_meo_thay_con_cho(sủa, function(chạy) { con_cho_bat_duoc_con_meo(đấm nó, function() { // Đấm tới tấp }) }); }); // Dùng promise, code gọn nhẹ dễ đọc con_chó_gặp_con_mèo .then(con_meo_thay_con_cho) .then(con_cho_bat_duoc_con_meo) .then(function() { // Đấm tới tấp }); |
2. Xử lý lỗi:
1 2 3 4 5 6 7 8 9 10 |
con_chó_gặp_con_mèo .then(con_meo_thay_con_cho) .then(con_cho_bat_duoc_con_meo) .then(function() { // Đấm tới tấp }) .catch(function(error) { console.log(error) // Bị chủ con mèo tóm được console.log('Ẳng Ẳng'); }); |
Chỉ cần 1 trong 3 hàm then kia lỗi, ngay lập tức chạy vào hàm catch để chúng ta bắt lỗi và xử lý.
Tổng kết:
Bài viết tạm thời đến đây vì nó khá nặng về kĩ thuật, nuốt khó trôi. Mình sẽ ra tiếp các bài sau đi vào chi tiết hơn và nâng cao về Promise, Async – Await trong ES7. Cảm ơn các bạn đã quan tâm và nếu có câu hỏi hay đóng góp gì hãy comment ở dưới và mình sẽ phản hồi lại nhanh nhất có thể 😁.
2 comments
Pingback: Bất đồng bộ trong Javascript – Promise nâng cao
Pingback: Bất đồng bộ trong Javascript chưa bao giờ đơn giản đến thế với Async - Await