1. Promise trong Javascript là gì?

Một Object Promise trong Js đại diện cho một giá trị ở thời điểm hiện tại có thể chưa tồn tại, nhưng sẽ được xử lý và có giá trị vào một thời gian nào đó trong tương lai. Promise là một cách tốt để xử lý các hoạt động không đồng bộ. Nó được sử dụng để kiểm tra việc hoạt động không đồng bộ có được hoàn thành thành công hay không.

Promise có thể 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.

Một Promise sẽ bắt đầu ở trạng thái đang chờ xử lý. Điều đó có nghĩa là quá trình này chưa hoàn tất. Nếu thao tác thành công, quá trình kết thúc ở trạng thái hoàn thành. Và, nếu xảy ra lỗi, quá trình sẽ kết thúc ở trạng thái bị từ chối.

Ví dụ: Khi ta yêu cầu dữ liệu từ máy chủ bằng cách sử dụng một Promise , nó sẽ ở trạng thái chờ xử lý. Khi dữ liệu đến thành công, nó sẽ ở trạng thái hoàn thành. Nếu lỗi xảy ra, thì nó sẽ ở trạng thái từ chối.

Vậy 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).

Các phương thức của promise trong Js:

Phương thức Mô tả
all(iterable) Chờ đợi tất cả các Promise được giải quyết hoặc bị từ chối.
allSettled(iterable) Chờ đợi cho đến khi tất cả Promise được giải quyết hoặc từ chối.
any(iterable) Trả về giá trị của Promise ngay khi có bất kỳ Promise nào được hoàn thành.
race(iterable) Chời đợi cho tới khi bất kỳ Promise nào được giải quyết hoặc từ chối.
reject(reason) Trả về đối tượng Promise mới mà bị từ chối.
resolve(value) Trả về đối tượng Promise mới mà được giải quyết xong.
catch() Gắn thêm hàm Callback xử lý bị từ chối.
then() Gắn thêm hàm Callback xử lý được giải quyết xong.
finally() Gắn thêm hàm xử lý cho một Promise.

2. Tạo một Promise trong JavaScript

Để tạo một Promise bạn sử dụng cú pháp sau:

let a = new Promise(function(resolve, reject){
     //Đoạn mã
});

Chúng ta có thể sử dụng hàm tạo Promise() và nhận một hàm làm đối số. Hàm này cũng chấp nhận hai hàm là resolve()reject() . Nếu Promise trả về thành công, hàm resolve() được gọi. Và, nếu có lỗi xảy ra, hàm reject() được gọi.

Ví dụ:

// Part 1
var isMomHappy = false;
// Promise
var willIGetNewPhone = new Promise(
function (resolve, reject) {
if (isMomHappy) {
var phone = {
brand: 'Samsung',
color: 'Màu Trắng'
};
resolve(phone); // fulfilled
} else {
var reason = new Error('Mẹ không vui');
reject(reason); // reject
}
}
);

Hoặc một ví dụ nữa

let duocGoiSach = true; 
let sach = new Promise(function (resolve, reject){
  if(duocGoiSach) {
    resolve("Bạn đã được chị gửi sách. :)");
  } else {
    reject("Bạn không được chị gửi sách. :(");
  }
});
console.log(sach)

Lúc này bạn có thể thấy trạng thái của promise đã được thay đổi sang resolved và giá trị của promise là một chuỗi mà chúng ta đã truyền vào cho hàm resolve() . Bạn có thể hình dung cách chạy của nó như sau:

  • Exexutor sẽ được gọi tự động và ngay lập tức khi new Promise được chạy.
  • Executor nhận hai đối số là resolvereject . Những hàm được truyền vào này sẽ được định nghĩa lại thông qua Js. Chúng ta chỉ gọi chúng sau khi đã sẵn sàng.
  • Bên trong executor chúng ta sẽ gọi hàm resolve() nếu chương trình thực hiện thành công hoặc gọi hàm reject() nếu chương trình xảy ra lỗi

3. Phương thức Then trong Promise

Thenable không có gì to tác mà nó 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 ở RejectResolve . 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 .

Cú pháp của phương thức then() như sau:

promise.then(
  function(result) { /* Xử lý kết quả thành công*/ },
  function(error) { /* Xử lý kết quả bị lỗi */ }
);

Điều quan trọng nhất, cơ bản là  .then . Promise.then() nhận hai đối số, một lệnh gọi lại cho thành công và một cho thất bại. Cả hai đều là tùy chọn, vì vậy bạn có thể thêm lệnh gọi lại chỉ khi thành công hoặc thất bại.

Ví dụ: đây là một phản ứng đối với một lời hứa được giải quyết thành công:

let promise = new Promise(function(resolve, reject) {
  setTimeout(() => resolve("done!"), 1000);
});

// resolve runs the first function in .then
promise.then(
  result => alert(result), // shows "done!" after 1 second
  error => alert(error) // doesn't run
);

Và trong trường hợp từ chối:

let promise = new Promise(function(resolve, reject) {
  setTimeout(() => reject(new Error("Whoops!")), 1000);
});

// reject runs the second function in .then
promise.then(
  result => alert(result), // doesn't run
  error => alert(error) // shows "Error: Whoops!" after 1 second
);

Nếu chúng ta chỉ quan tâm đến việc hoàn thành thành công, thì chúng ta chỉ có thể cung cấp một đối số hàm để .then :

let promise = new Promise(resolve => {
  setTimeout(() => resolve("done!"), 1000);
});

promise.then(alert); // shows "done!" after 1 second

4. Phương thức Catch trong Promise

Phương thức catch() được sử dụng với hàm Callback khi Promise bị từ chối hoặc nếu xảy ra lỗi. Nếu chúng ta chỉ quan tâm đến lỗi, thì chúng ta có thể sử dụng null làm đối số đầu tiên : .then(null, errorHandlingFunction) . Hoặc chúng ta có thể sử dụng .catch(errorHandlingFunction), hoàn toàn giống nhau:

let promise = new Promise((resolve, reject) => {
  setTimeout(() => reject(new Error("Whoops!")), 1000);
});

//.catch (f) giống như promise.then (null, f)
promise.catch(alert); // hiển thị "Lỗi: Rất tiếc!" sau 1 giây

Một ví dụ nữa:

let vi_du = new Promise(function (resolve, reject) {
   reject('Từ chối');
});
vi_du.then(
    function vi_du2() {
        console.log("Xử lý tiếp");
    },
 )
.catch(
    function vi_du3() {
        console.log('Lỗi xảy ra');
    }
);

Trong chương trình trên, Promise bị từ chối. Và phương thức catch() được sử dụng cho Promise để xử lý lỗi.

Gọi .catch(f) này là một sự tương tự hoàn toàn .then(null, f) , nó chỉ là một tốc ký(cách viết gọn).

5. Phương thức finally trong Promise

Ta cũng có thể sử dụng phương thức finally() với các Promise . Phương thức finally() được thực thi khi Promise bất kể được giải quyết thành công hoặc bị từ chối.

.finally(f) tương tự như .then(f, f) trong ngữ cảnh này f có ý nghĩa luôn luôn chạy khi lời hứa được giải quyết: có thể giải quyết hoặc từ chối.

Ví dụ:

let vi_du = new Promise(function (resolve, reject) {
    resolve('Xử lý thành công');
});
vi_du.finally(
    function finalFunc() {
        console.log('Được thực thi xong');
    }
);

6. Ví dụ cụ thể về Promise

Những ví dụ cụ thể hơn về Promise nhé

Đang chờ hết thời gian chờ

<script>
const myPromise = new Promise(function(myResolve, myReject) {
  setTimeout(function(){ myResolve("Lập Trình Từ Đầu"); }, 3000);
});

myPromise.then(function(value) {
  document.write(value);
});
</script>

Đang đợi một tập tin

<script>
function myDisplayer(some) {
  document.write(some);
}

let myPromise = new Promise(function(myResolve, myReject) {
  let req = new XMLHttpRequest();
  req.open('GET', "mycar.html");
  req.onload = function() {
    if (req.status == 200) {
      myResolve(req.response);
    } else {
      myReject("File not Found");
    }
  };
  req.send();
});

myPromise.then(
  function(value) {myDisplayer(value);},
  function(error) {myDisplayer(error);}
);
</script>