Categories
Tech

Promise và cách sử dụng như thế nào ?

 

Promise là gì ?

Trong quá trình làm việc với javascript, chúng ta hẳn không ít lần làm việc Promise và xử liệu dữ liệu bất đồng bộ. Vậy Promise là gì, và xử lý bất đồng bộ như thế nào.

Trong Javascript, Promise là một cơ chế giúp thực thi các tác vụ bất đồng bộ tránh rơi vào tình trạng các hàm callback gọi lồng nhau ở quá nhiều tầng ảnh hưởng tới quá trình xử lý của hệ thống.

Các trạng thái của promise:

Promise có 3 trạng thái chính:

  • Fulfilled : Là tình trạng của promise khi được resolved thành công.
  • Rejected : Là trạng thái của promise khi bị reject
  • Pending: Là trạng thái của promise trong khi đang chờ trả về 1 trong 2 trạng thái trên.

Sử dụng Promise như thế nào ?

Khởi tạo 1 hàm sử dụng Promise:

const tes = new Promise((resolve, reject) => {});

Promise gồm có 2  hàm : resolve và reject

-resolve : Hàm được gọi khi promise hoàn thành.

-reject : Hàm sẽ được gọi khi có lỗi xảy ra.

Cụ thể với ví dụ sau:

const tes = new Promise((resolve, reject) => {

        $.ajax({

            url: 'http://jsonplaceholder.typicode.com/todos',

            type: 'GET',

            dataType: 'jsonp',

            success: function(data) {

                resolve(data);

            },

            error: function(error) {

                reject(error);

            },

        });

    });

Trong ví dụ trên, mình khai báo một promise xử lý dữ liệu Ajax.  Dữ liệu trả về là một Promise dạng Object.

Promise cung cấp phương thức .then() để chúng ta truy xuất dữ liệu từ Promise Object.

Ví dụ: 
tes.then((success, error) => {});

Phương thức .then() nhận vào 2 hàm là success và error .

  • Success : được gọi khi promise hoàn thành
  • Error : được gọi khi promise có lỗi.

Cụ thể :

tes.then((success, error) => {

            if (error) return new Error(‘error’);

            // tra ve neu thanh cong

           return success;

});

Nối nhiều Promise lại với nhau

Trong quá trình xử lý dữ liệu, nhiều khi chúng ta cần xử lý các tiến trình chạy một các tuần tự theo một chiều nhất định, trong khi quá trình xử lý của các bước sau yêu cầu param đầu vào là kết quả của các bước trước đó. Để đảm bảo quá trình này đi theo logic mong muốn, chúng ta có thể sử dụng nối nhiều promise lại với nhau.

Ví dụ:

tes.then((success, error) => {

        if(error) return new Error('Lỗi rồi');

        console.log('step 1');

        return success;

    }).then((res2, err2)=> {

        console.log('Kết quả từ step 1: ' + res2);

        return 'step2';

    }).then((res3, err3)=> {

        console.log('Kết quả từ step 2: ' + res3);

        return 'step3';

    }).then((res4, err4)=> {

        console.log('Kết quả từ step 3: ' + res4);

        return 'step4';

    });

Kết quả console.log() nhận được:
step 1
index.html:25 Kết quả từ step 1: step1
index.html:28 Kết quả từ step 2: step2
index.html:31 Kết quả từ step 3: step3

Thông thường, ở hàm .then() thứ nhất trả về kết quả sẽ được nhận trong hàm .then() thứ 2. Nhưng nếu .then() thứ nhất trả về kết quả là một Promise thì hàm .then() thứ 2 phải chờ hàm .then() thứ nhất xử lý xong xuôi và trả về dữ liệu thì mới thực thi tiếp tục.

Phương thức .catch()

Như các bạn thấy ở các hàm .then() đều có 2 phương thức success và error, nếu thành công thường sẽ trả về phương thức thức nhất. Thất bại sẽ gọi tới hàm thứ 2. Tuy nhiên, có một cách để xử lý lỗi chung cho các hàm .then() là sử dụng hàm  .catch().

    tes.then((success) => {

        if(error) return new Error('Lỗi rồi');

        console.log('step 1');

        return 'step1';

    }).then((res2)=> {

        console.log('Kết quả từ step 1: ' + res2);

        return 'step2';

    }).then((res3)=> {

        console.log('Kết quả từ step 2: ' + res3);

        return 'step3';

    }).then((res4)=> {

        console.log('Kết quả từ step 3: ' + res4);

        return 'step4';

    }).catch((err) => {

        console.log('Hệ thống lỗi');

    });

Ở ví dụ trên, các bạn thấy ở phương thức .then() mình chỉ khai báo một hàm callback duy nhất. Vì vậy khi Promise bị lỗi, toàn bộ lỗi sẽ được đẩy xuống phương thức .catch() để xử lý.  Ở đây chúng ta có thể thực hiện các thao tác log lỗi hệ thống cần thiết.

Một số phương thức khác khi sử dụng promise

Promise.all()

Nếu như phương thức .then() nối các promise lại với nhau theo một thứ tự được người dùng định nghĩa thì ở phương thức .all() các promise phải được giải quyết trước khi phương thức .then() được thực hiện.

Ví dụ ta có 3 promise :

var ob1 = new Promise((resolve, reject) => { 
  setTimeout(resolve, 1000, "1"); 
}); 
var ob2 = new Promise((resolve, reject) => { 
  setTimeout(resolve, 2000, "2"); 
});
var ob3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 3000, "3");
});

Khi sử dụng .all()

Promise.all([ob1, ob2, ob3]).then(values => {
    console.log(values);
}).catch(()=> {
  console.log('error');
}); 

Khi cả 3 promise ob1, ob2, ob3 được thực hiện xong thì hàm .then() mới được gọi. Nếu 1 trong 3 bị lỗi thì  phương thức .catch() sẽ được gọi.

Promise.reject(reason)

Đây là phương thức rút gọn khi bạn cần khai báo một promise thất bại. Thay vì phải khai báo dài dòng như phần giới thiệu trên(dùng new Promise() ), thì phương thức này được promise cung cấp sẵn. Đầu vào của nó sẽ là một lý do hay một lỗi bạn muốn hiển thị.

Promise.reject(new Error('fail')).then(function() {
  // not called
}, function(error) {
  console.error(error);  });
Promise.resolve(value)

Cũng như phương thức reject() thì promise cung cấp sẵn một phương thức rút gọn để giúp tạo 1 promise resolve nhanh chóng. Đầu vào của hàm resolve sẽ là một giá trị cần sử dụng.

Ví dụ đơn giản với 1 promise resolve:

var p = Promise.resolve([1,2,3]);
p.then(function(v) {
  console.log(v[0]); // 1
});
Promise.finally()

Phương thức này thường được sử dụng sau phương thức .catch(). Ý nghĩa của phương thức này là lệnh trong phương thức này luôn được thực thì cho dù promise của bạn chạy có trả về lỗi hay trả về kết quả đúng.

Ví dụ:


Promise.all([ob1, ob2, ob3]).then(values => { 
  console.log(values);
}).catch(reason => { 
  console.log(reason)
}).finally(()=> {
   console.log('đóng trình duyệt');
});

Ở ví dụ trên bạn có thể thấy, mình sử dụng promise.all() để xử lý 3 promise ob1, ob2, ob3. Dù cho 3 promise này được xử lý như thế nào thì sau cùng phương thức .finally() sẽ được gọi.

Promise.race()

Phương thức này thường dùng để trả về những promise nào được xử lý nhanh nhất. Ví dụ bạn có 3 promise ob1, ob2, ob3 , nếu promise nào trong 3 cái này trả về trước sẽ được thực thi.

Promise.race([ob1, ob2, ob3]).then(values => { 
  console.log(values);
}).catch(reason => { 
  console.log(reason)
}).finally(()=> {
   console.log('đóng trình duyệt');
});

=> kết quả nhận được là 1 do object 1 được xử lý xong trước.

Tổng kết

Đây chỉ là những khái niệm cơ bản nhất về Promise và cách sử dụng, tuy không phải là đầy đủ nhất nhưng hy vọng giúp ích được các bạn mới làm quen với Promise hiểu được cơ bản về nó. Việc sử dụng Promise như thế nào còn tuỳ vào từng dự án và hướng đi của nhà phát triển.
Cảm ơn các bạn đã theo dõi. Mọi ý kiến đóng góp đều được hoan nghênh.

Nguồn:
https://viblo.asia/

Homepage