Bài 17: Hiểu rõ hơn về Promise trong Javascript - ES6

Promise là đề tài được tìm kiếm khá nhiều trong 2 năm gần đây, nhất là kể từ ngày AngularJS, NodeJS và các JS Framework khác ra đời bởi vì hầu hết chúng đều có sử dụng Promise để giải quyết xử lý bất đồng bộ (Async). Ở bài trước mình có giới thiệu sơ lược về cách sử dụng Promise rồi, tuy nhiên mình vãn đưa ra bài viết này bởi mình cần làm sáng tỏ một số vấn đề khác nữa.

Nếu bạn đang xem bài này lần đầu tiên thì mình nghĩ bạn nên quay lại đọc bài Promise trong Javascript sẽ giúp bạn dễ dàng follow hơn.

1. Ba trạng thái Pending - Fulfilled - Rejected

Ở bài trước mình có giới thiệu 3 trạng thái của Promise đó là pending, fulfilled rejected, đây là ba trạng thái mà bất kì một Promise nào cũng phải có.

Pending

Pending là trạng thái khi bạn khởi tạo một Promise nhưng chưa thiết lập kết quả cho nó, tức là chưa sử dụng resolve và reject.

var promise = new Promise(function(resolve, reject){

});

console.log(promise);

Kết quả:

Fulfilled

Fulfilled còn được gọi là resolved, đây là trạng thái của Promise đã thành công, trạng thái này xảy ra khi bạn sử dụng resolve.

var promise = new Promise(function(resolve, reject){
    resolve();
});

console.log(promise);

Kết quả:

Rejected

Rejected là trạng thái thao tác thất bại, trạng thái này xảy ra khi bạn sử dụng reject. Khi bạn sử dụng reject thì bắt buộc phải khai báo hành động xử lý cho nó (tức sử dụng then hoặc catch).

var promise = new Promise(function(resolve, reject){
    reject();
});

promise.catch(function(){
    // Something
});

console.log(promise);

Kết quả:

2. Thenable liên tiếp

Phương thức then() có nhiệm vụ tiếp nhận kết quả trả về của promise và nó cũng return về một promise nên bạn có thể dùng nhiều lần liên tiếp với nhau.

var promise = new Promise(function(resolve, reject){
    resolve();
});

promise.then(function(){
            console.log(1);
        })
        .then(function(){
            console.log(2);
        })
        .then(function(){
            console.log(3);
        });

Kết quả:

Việc đặt thứ tự các phương thức rất quan trọng nhé các bạn. Nếu hành động của promise trả về là một Reject thì sẽ có hai trường hợp xảy ra như sau:

Trường hợp 1: Nếu trong phương thức then() nào đó có sử dụng callback function Reject thì các phương thức then() ở phía sau sẽ là một Fulfilled, nghĩa là nó sẽ chạy ở callback function Resolve.

var promise = new Promise(function(resolve, reject){
    reject();
});

promise.then(function(){
            console.log(1);
        })
        .then(function(){
            console.log(2);
        }, function(){
            console.log('Error!')
        })
        .then(function(){
            console.log(3);
        });

Kết quả:

Nếu chiếu theo quy luật thì ở biến promise mình đã sử dụng Reject nên suy ra ở then() tham số callback thứ hai sẽ hoạt động. Điều này hoàn toàn đúng với phương thức then() thứ hai, vì vậy nó in ra chư Error!. Tuy nhiên nhảy qua phương thức then() thứ tư thì nó lại chạy phần callback Resolve nên in ra số 3.

Trường hợp 2: Bạn sử dụng catch để bắt lỗi, lúc này chỉ có phương thức catch() là hoạt động.

var promise = new Promise(function(resolve, reject){
    reject();
});

promise.then(function(){
            console.log(1);
        })
        .then(function(){
            console.log(2);
        })
        .then(function(){
            console.log(3);
        })
        .catch(function(){
            console.log('Error!')
        });

Kết quả:

Ôi tới đây thì mình đã mắc một sai lầm nghiêm trọng. Thật ra thì hai trường hợp kia chỉ là lý luận theo hướng mắt thấy tai nghe nên nó không đúng đâu các bạn nhé, vấn đề nằm ở câu chốt dưới này :)

Khi sử dụng thenable liên tiếp thì kết quả return của phương thức then() hiện tại sẽ quyết định trạng thái của phương thức  then() tiếp theo. Ví dụ then() phía trên return về một Promise Rejected thì then() phía dưới sẽ nhận một trang thái Rejected.

Mình sẽ lấy một ví dụ như sau:

asyncPromise1()
        .then(function () {
            return asyncPromise2();
        })
        .then(function () {
            return asyncPromise3();
        })
        .catch(function (err) {
            return asyncRecovery1();
        })
        .then(function () {
                return asyncPromise4();
            }, function (err) {
                return asyncRecovery2();
            }
        )
        .catch(function (err) {
            console.log("Đừng lo lắng gì cả :)");
        })
        .then(function () {
            console.log("Mọi thứ đã xong!");
        });

Kết quả của đoạn code đó phụ thuộc vào các Async mà nó return về. Và sau đây là bảng mô tả các trường hợp xảy ra.

Trong hình này đường màu xanh mô tả cho Async Promise return về một Fulfilled và màu tím mô tả cho Asycn Promise return về một Rejected.

Lấy một ví dụ chạy thực luôn cho các bạn xem nhé.

var promise = new Promise(function(resolve, reject){
    resolve();
});

promise
    .then(function(){
        return new Promise(function(resolve, reject){
            reject();
        });
    })
    .then(function(){
        console.log('Success!');
    })
    .catch(function(){
        console.log('Error!');
    });

Kết quả:

then() thứ nhất return về một Reject Promise nên then() thứ hai không chạy, và trạng thái bây giờ là Rejected nên catche sẽ được chạy => in ra chữ Error!.

Vậy là hết rồi đó !

3. Lời kết

Rõ ràng Promise trong Javascript nói chung và trong ES6 nói riêng rất phức tạp phải không các bạn, hôm nay mình mất đúng một ngày mới biên soạn xong hai bài này đấy :)

Việc hiểu nguyên tắc hoạt động của Promise rất quan trọng, nếu  không bạn sẽ rất dễ mắc phải các lỗi về Callback Hell  đấy. Cuối cùng chúc bạn học tốt và luôn ủng hộ freetuts.net nhé.

Tài liệu chỉ mang tính chất tham khảo, mình không cam kết các nội dung trên website, vì vậy không được sử dụng để in ấn hay kinh doanh.
Hãy để lại link bài viết gốc khi chia sẻ bài viết này, mình sẽ report DMCA với những website vi phạm nội dung bản quyền mà mình đã đưa ra.

Nguồn: freetuts.net

Profile photo of adminTheHalfHeart

TheHalfHeart

Có sở thích viết tuts nên đã từng tham gia viết ở một số diễn đàn, đến năm 2014 mới có điều kiện sáng lập ra freetuts.net. Sinh năm 90 và có 1 vợ 2 con, thích ca hát và lập trình.

ĐĂNG BÌNH LUẬN: Đăng câu hỏi trên Facebook để được hỗ trợ nhanh nhất.