Giới thiệu Promise

Giới thiệu Promise

Promise là một object đại diện cho thao tác bất đồng bộ sẽ trả về thành công hoặc thất bại. Các thao tác của chương trình Javascript được chia ra là nhanh (đồng bộ - synchronous) và chậm (bất đồng bộ - asynchronous).

Thao tác bất đồng bộ là thao tác với đĩa cứng như file, cơ sở dữ liệu, giao tiếp với mạng, hoặc là giao tiếp với các chương trình khác. Thao tác bất đồng bộ là thường phải chờ một khoảng thời gian (không biết trước) mới trả về kết quả. Kết quả có thể thành công hoặc thất bại. Các thất bại xảy ra ví dụ như file không tìm thấy, cơ sở dữ liệu không tồn tại.

Thao tác đồng bộ là các thao tác liên quan tới CPU và RAM. Thao tác này luôn nhanh và chúng ta giả sử chúng là không có lỗi.

Chương trình JavaScript phân chia rất rõ ràng thành hai phần: các thao tác thông thường là đồng bộ và các thao tác bất đồng bộ. Các thao tác bất đồng bộ có thể được đại diện bởi một đối tượng tên là Promise. Các thao tác bất đồng bộ này luôn chạy sau khi các thao tác đồng bộ chạy xong. Vì chúng ta luôn giả sử rằng thao tác bất đồng bộ chạy chậm hơn nên ưu tiên cho thao tác đồng bộ. Cơ chế này có tên là event loop (vòng lặp sự kiện) trong trình thông dịch Javascript.

Hàm setTimeout()

Hàm setTimeout(asyncFunction, miliSecond) là có tham số asyncFunction là hàm bất đồng bộ. Tham số asyncFunction của hàm này sẽ chạy khi các chương trình đồng bộ chạy xong trong thời gian miliSecond (mili giây).

Thao tác bất đồng bộ này không được quản lý bởi Promise mà sử dụng một hàm callback - cũng chính là tham số của hàm setTimeout().

1
2
3
4
setTimeout(function() {
  console.log('Thao tác bất đồng bộ đây');
}, 0);
console.log('Thao tác đồng bộ');

Hàm trên sẽ chạy theo thứ tự từ đồng bộ đến bất đồng bộ nên sẽ in ra:

"Thao tác đồng bộ"
"Thao tác bất đồng bộ đây"

Trong các ví dụ bài viết, chúng ta sẽ lấy hàm setTimeout() để giả lập các thao tác bất đồng bộ như đọc file, lấy dữ liệu trên mạng về từ một Url.

Hàm setTimeout còn có dạng setTimeout(asyncFunction, miliSecond, ...prams) trong đó prams là danh sách tham số của hàm asyncFunction.

Tạo Promise

Một promise luôn ở trong một trong ba trạng thái:

  • Trạng thái chờ - pending (chưa thực thi xong thao tác bất đồng bộ)
  • Trạng thái thành công - fulfilled (thực thi thao tác bất đồng bộ thành công)
  • Trạng thái thất bại - rejected (thực thi thao tác bất đồng bộ thất bại)

Tham số khi tạo Promise là hàm có hai tham số resolvereject. Chúng ta gọi resolve() khi thao tác thành công và gọi hàm reject() khi thao tác thất bại.

Ví dụ sau đây đọc dữ liệu từ url /data/sample.json sau đó trả về một Promise. Sau đó chúng ta sẽ in ra nội dung của url được lấy từ promise này.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
let myFirstPromise = new Promise((resolve, reject) => {
  // lấy dữ liệu trên mạng từ url
  const URL = '/data/sample.json';
  fetch(URL).then(response => {
    // thành công
    resolve(response); // hàm then sẽ nhận tham số response
  }).catch(error => {
    // thất bại
    reject(error); // hàm catch sẽ nhận tham số error
  });
});

myFirstPromise.then((response) => {
  console.log(response.statusText); // OK
  return response.text().then(function(text) {
    // hiển thị nội dung
    console.log(text);
  });
}).catch(error => {
  // in ra lỗi
  console.error(error.toString());
});

Bạn hãy thử thay đổi URL thành https://google.com.vn để xem kết quả là gì.

Hàm constructor Promise, then và catch

  • Hàm constructor của Promise là một hàm đồng bộ, trả về một Promise.
  • Khi tạo constructor Promise thì tham số construct sẽ được chạy ngay lập tức.
  • Promise.prototype.then() là hàm sẽ chạy khi Promise chạy thành công, trả về một Promise.
  • Promise.prototype.catch() là hàm sẽ chạy khi Promise chạy lỗi, trả về một Promise.
  • Promise.prototype.finally() là hàm sẽ chạy khi Promise chạy thành công hay lỗi, cũng trả về một Promise.

Tham số của ba hàm then, catch, finally là hàm số bất đồng bộ.