Tìm hiểu về promise trong ES6

Promise được đưa vào Javascript từ ES6, đây có thể coi là một kỹ thuật nâng cao giúp xử lý vấn đề bất đồng bộ hiệu quả hơn. Trước đây kết quả của một tác vụ đồng bộ và bất đồng bộ sẽ trả về một kiểu dữ liệu nào đó hoặc thực hiện một Callback Function. Với trường hợp thực hiện Callback Function thì sẽ dễ xảy ra lỗi Callback Hell, nghĩa là gọi callback quá nhiều và lồng nhau nên dẫn đến không kiểm soát được chương trình hoặc bộ nhớ không đủ để hoạt động. Và trong bài viết này chúng ta sẽ tìm hiểu về Promise, một package được đưa vào từ ES6 giúp giải quyết vấn đề Callback Hell này.

1. Promise là gì ?

  • Promise sinh ra để xử lý kết quả của một hành động cụ thể, kết quả của mỗi hành động sẽ là thành công hoặc thất bại và Promise sẽ giúp chúng ta giải quyết câu hỏi "Nếu thành công thì làm gì? Nếu thất bại thì làm gì?". Cả hai câu hỏi này ta gọi là một hành động gọi lại (callback action)

2. Các trạng thái của promise

Khi một Promise được khởi tạo thì nó có một trong ba trạng thái sau:

  • Fulfilled: hành động xử lý xong và thành công
  • Rejected: hành động xử lý xong và thất bại
  • Pending: hành động đang chờ xử lý hoặc bị từ chối

Trong đó hai trạng thái RejectFulfilled ta gọi là Settled, tức là đã xử lý xong.

3. Cách tạo 1 promise

  • Để tạo 1 promise chúng ta sử dụng cú pháp sau:
  •       var promise = new Promise(function (resolve, reject) {
          });
    
    
Trong đó:

* `resolve` là một hàm callback xử lý cho hành động thành công.
* `reject` là một hàm callback xử lý cho hành động thất bại.
# 4. Thenable trong promise
* `Thenable` là một phương thức ghi nhận kết quả của trạng thái (thành công hoặc thất bại) mà ta khai báo ở `Reject` và `Resolve`. Nó có hai tham số truyền vào là 2 callback function. Tham số thứ nhất xử lý cho `Resolve` và tham số thứ 2 xử lý cho `Reject`.

* ```JavaScript
        var promise = new Promise(function(resolve, reject){
            resolve('Success');
            // OR
            reject('Error');
        });

        promise.then(
                function(success){
                    // Success
                },
                function(error){
                    // Error
                }
        );

5. Catch trong promise

then có hai tham số callbacks đó là successerror. Tuy nhiên bạn cũng có thể sử dụng phương thức catch để bắt lỗi. Cú pháp:

  •       promise.then().catch();
    
    

Ví dụ:
* ```JavaScript
        var promise = new Promise(function(resolve, reject){
            reject('Error!');
        });

        promise.then(function(message){
            console.log(message);
        })
        .catch(function(message){
            console.log(message);
        });

6. Một vài ví dụ ứng dụng promise

Giả sử ta có một tác vụ muốn delay 5s rồi in ra chữ “LẬP” tiếp đó 3s in ra chú “TRÌNH” sau cùng 2s in ra chữ “JAVASCRIPT”

  • Nếu sử dụng hàm setTimeout thì chúng ta có thể viết như sau:
    setTimeout(function(){
       console.log('LẬP');
       setTimeout(function(){
           console.log('TRÌNH');
           setTimeout(function(){
              console.log('JAVASCRIPT');
          },2000);
       },3000);
    }, 5000);
  • Nhìn khá là rắc rối đúng không nào. Chúng ta có thể viết lại bằng promise như sau.
    function handleTimeout(timeout) {
        return new Promise(function (resolve, reject) {
            setTimeout(resolve, timeout);
        });
    }

    var xxx = handleTimeout(5000);
    xxx.then(function () {
        console.log('LẬP');
    })
    .then(function () {
        return handleTimeout(3000);
    })
    .then(function () {
        console.log('TRÌNH')
    })
    .then(function () {
        return handleTimeout(1000);
    })
    .then(function () {
        console.log('JAVASCRIPT');
    });

Tiếp thêm 1 ví dụ ứng dụng promise. Lần này ta sẽ sử dụng FileReader để upload nhiều file ảnh. Yêu cầu là chỉ được upload những file có định dạng ảnh và đếm xem có bao nhiêu lỗi về định dạng file, bao nhiêu lỗi về load error file, bao nhiêu file được load success.

    <input type="file" multiple="multiple" class="upload"/>
    $(function () {
        $(document).on('change', '.upload', function (event) {
            var files = event.target.files;
            var countTypeError = 0;
            var countLoadError = 0;
            var countLoadSuccess = 0;
            var promises = [];
            $.each(files, function (index, file) {
                promises.push(fileReader(file));
            });

            var result = Promise.all(promises).then(function (value) {
                $.each(value, function (index, object) {
                    if (object.hasTypeError) {
                        countTypeError ++;
                    }

                    if (object.hasLoadError) {
                        countLoadError ++;
                    }

                    if (object.hasLoadSuccess) {
                        countLoadSuccess ++;
                    }
                });
            });

            result.then(function () {
                console.log('countTypeError', countTypeError);
                console.log('countLoadError', countLoadError);
                console.log('countLoadSuccess', countLoadSuccess);
            });
        });

        function fileReaderPromise(file) {
            return new Promise(function (resolve, reject) {
                if (/^image/.test(file.type)) {
                    var reader = new FileReader();
                    reader.onload = function () {
                        resolve({ hasLoadSuccess: true });
                    };

                    reader.onerror = function () {
                        reject({ hasLoadError: true });
                    };
                } else {
                    reject({ hasTypeError: true });
                }
            });
        }
    });

Hy vọng qua bài viết này sẽ giúp bạn hiểu thêm về promise trong ES6

Nguồn tham khảo: https://viblo.asia/asvenus/posts/p1PvQ3JAMldr

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise