Giới thiệu về Promise trong JavaScript (ES6)
Bài đăng này đã không được cập nhật trong 3 năm
Xin chào mọi người, Chắc hẳn trong mỗi người lập trình viên chúng ta, Khi lập trình với ngôn ngữ Javascript đều thấy được một vấn đề là Bất đồng bộ
. Để giải quyết vấn đề này, cách cơ bản nhất là chúng ta sử dụng Callback
. Nhưng có một vấn đề xảy ra, đó là việc sử dụng qua nhiều callback
dẫn dến tình trạng code rất rối, khó maintain. Người ta còn gọi vấn đề này là CallbackHell
.
Ví dụ:
getData(function(a){
getMoreData(a, function(b){
getMoreData(b, function(c){
getMoreData(c, function(d){
getMoreData(d, function(e){
...
});
});
});
});
});
Nếu cứ dùng callback
lồng nhau thế này thì thực sự không ổn. Để giải quyết vấn đề trên Promise
đã được ra đời, Nó giải quyết vấn đề CallbackHell
hiệu quả bằng cách tạo các Promise Chain
, Mình sẽ giới thiệu về Promise Chain sau. Từ phiên bản JavaScript ES6
Promise
đã được giới thiệu đến lập trình viên và đã được cho vào thư viện chuẩn của Javascript
và các base Promise API
hầu hết đã có trên các trình duyệt hiện đại.
Khởi tạo một promise
var myFirstPromise = new Promise(function(resolve, reject){
// do something asynchronous which eventually calls either: (1)
//
// resolve(someValue); // fulfilled (2)
// or
// reject("failure reason"); // rejected (3)
});
Khởi tạo một đối tượng Promise
với tham số là một function với 2 tham số là 2 callback resolve
và reject
.
Dòng 1:
pending
(Đang xử lý) trạng thái thứ nhất củaPromise
, đoạn này chứa các đoạn code bất đồng bộ, Ví dụ lấy dữ liệu từ phía server và hiển thị kết quả ra màn hình. Dòng 2:fulfilled
: (Xử lý hoàn thành) trạng thái thứ hai củaPromise
, đoạn này chứa một callbackresolve()
implement các đoạn code đồng bộ bên trong (Nếu xử lý code bất đồng bộ phía trên thành công). Dòng 3:rejected
: (Xử lý thất bại) trạng thái thứ ba củaPromise
, đoạn này chứa đoạn callbackreject()
implement các đoạn code đồng bộ bên trong (Nếu xử lý code bất đồng bộ phía trên thất bại).
Implement Promise
Giờ hãy đi vào một ví dụ thực tế đầu tiên để hiểu hơn về 3 trạng thái trên:
var myFirstPromise = new Promise(function(resolve, reject){
var request = new XMLHttpRequest();
request.open('GET', 'https://www.random.org/integers/?num=1&min=1&max=6&col=1&base=10&format=plain&rnd=new');
request.onload = function() {
if (request.status == 200) {
resolve(request.response); // xử lý thành công khi server response thành công.
} else {
reject(Error(request.statusText)); // xử lý thất bại khi server response lỗi.
}
};
request.onerror = function() {
reject(Error('Error fetching data.')); // xử lý thất bại khi request lỗi.
};
request.send(); //gửi request
});
});
Chúng ta khởi tạo một Promise
.
Pending: đoạn code bất đồng bộ chính là đoạn khởi tạo và gửi request lên server. Ở đây chúng ta gửi
GET HTTP
tới random.org để lấy 1 số random từ 0 -> 10 Resolve: Hàmresolve()
Reject: Hàmreject()
Chú ý:resolve
vàreject
không phải là 2 hàm cố định, chúng ta có thể đổi tên hàm nếu muốn, Nhưng vì ý nghĩa chúng khá sát nên theo mình không nên đổi. Chúng ta đã tạo đối tượngPromise
xong, Nhưng nó chưa đượcImplement
:
promise.then(function(data) {
console.log('Got data! Promise fulfilled.');
console.log('Random number is: ' + data);
}, function(error) {
console.log('Promise rejected.');
console.log(error.message);
});
Để implement
một Promise
chúng ta sử dụng then()
method, một Prototype
của Promise
, với 2 tham số là 2 hàmresolve()
(in ra data) và reject()
(xử lý lỗi)
Ngoàithen()
Promise
còn cung cấp một Prototype
khác để xử lý lỗi, Bất kì Exception
nào sinh ra đều được xử lý, đó là hàm catch()
Vậy chúng ta có thể viết lại dòng Implement Promise
trên theo một cách khác, Mình nghĩ nên dùng cách này vì code rõ ràng, dễ hiểu và đặc biệt xử lý được tất cả ngoại lệ, Đương nhiên là chúng ta có thể dùng try()
catch()
để bắt lỗi nhưng điều đó là không nên vì catch()
trong Promise
đã có rồi.
promise.then(function(result) {
console.log('Got data! Promise fulfilled.');
console.log('Random number is: ' + data);
}).catch(function(error) {
console.log('Error occurred!', error);
});
Promise chain
Promise chain
chính là giải pháp cho CallbackHell
mình đã đề cập ở trên, chúng ta đi thẳng vào một ví dụ:
var firstMethod = function () {
var promise = new Promise(function (resolve, reject) {
setTimeout(function () {
console.log('first method completed');
resolve({data: '123'});
}, 2000);
});
return promise;
};
var secondMethod = function (someStuff) {
var promise = new Promise(function (resolve, reject) {
setTimeout(function () {
console.log(someStuff);
resolve({newData: someStuff.data + ' some more data'});
console.log(someStuff);
}, 2000);
});
return promise;
};
var thirdMethod = function (someStuff) {
var promise = new Promise(function (resolve, reject) {
setTimeout(function () {
console.log('third method completed');
resolve({result: someStuff.newData});
console.log(someStuff);
}, 3000);
});
return promise;
};
firstMethod().then(secondMethod).then(thirdMethod); (implement)
Chúng ta khởi tạo 3 function và cả 3 function đều trả về một promise object
.
Đầu tiên chúng ta chạy dòng (implement)
Sau đây mình xin phân tích các luồng xử lý của đoạn code trên.
firstMethod() được chạy: Một promise object
được khởi tạo.Promise
này khi và chỉ khi được implement bằng method then()
. Nó chứa 1 function timeout sau 2000 giây nó sẽ console ra dòng 'first method completed' và thực thi tiếp resolve()
function với biến truyền vào là chuỗi JSON {data: '123'}
. (1)
firstMethod().then(secondMethod): Bản thân firstMethod()
trả về một object chính là promise_1, Điều này tương đương với promise_1.then(secondMethod)
với secondMethod chính là resolve()
function ở (1), someStuff truyền vào ở đay chính là JSON {data: '123'}
ở (1)
. Tiếp tục secondMethod
sẽ trả về một đối tượng promise
khác, điều này tương đương với firstMethod().then(secondMethod)
sẽ trả về 1 object promise_2
firstMethod().then(secondMethod).then(thirdMethod): điều này tương đương với promise_2.then(thirdMethod)
Chúng ta có thể thấy các đoạn code tạo ra 1 chuỗi các promise implement bằng method then(), đương nhiên chúng ta có thể catch()
sau mỗi then()
để nó xử lý exception
:
Ảnh: https://images.viblo.asia/ae3d43d1-0748-4770-a50b-29a8c4c78e16.png
Tổng kết
Trên đây là những kiến thức nho nhỏ về base của Promise, Một cách tốt hơn để xử lý bất đồng bộ trong javascript, Xin cảm ơn!
Tham khảo
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise https://viblo.asia/p/gioi-thieu-ve-promise-trong-javascript-mrDGMJVPezL
All rights reserved