06/04/2021, 14:48

Hiểu rõ hơn về Promise trong Javascript - ES6 - Javascript nâng cao

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 ...

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ả:

pending status promise png

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ả:

resolve status promise png

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ả:

reject status promise png

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ả:

thenable lien tiep trong promise png

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ả:

thenable lien tiep trong promise 1 png

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ả:

thenable lien tiep trong promise 2 png

Ô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 :)

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.

thenable lien tiep trong promise 3 png

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ả:

thenable lien tiep trong promise 4 png

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ộ Zaidap.com.net nhé.

Bùi Văn Nam

27 chủ đề

7090 bài viết

Cùng chủ đề
0