Tìm hiểu về JavaScript Promise thông qua ví dụ

Trong chủ đề bất đồng bộ (asynchronous) JavaScript của học JavaScript cơ bản thì chúng ta đã tìm hiểu về một số kiến thức như: setTimeout() trong JavaScript là gì?, Callback Function trong JavaScript là gì? tại sao lại được sử dụng nhiều như vậy?,… hôm nay mình xin giới thiệu đến các bạn bài viết về Promise trong JavaScript nhé!

Trong JavaScript, promise dùng để xử lý những vấn đề liên quan đến asynchronous hay bất đồng bộ. Nếu không xử lý bất đồng bộ thì các đoạn code chúng ta viết sẽ không chạy đúng trình tự và như vậy có thể dẫn đến các lỗi không mong muốn 😀.

Một promise có thể có một trong ba trạng thái:

  1. Pending
  2. Fulfilled
  3. Rejected

Promise sẽ bắt đầu ở trạng thái pending (chờ xử lý). Điều đó có nghĩa là quá trình này chưa hoàn thành. Nếu xử lý thành công, quá trình sẽ kết thúc ở trạng thái fulfilled (hoàn thành). Nếu xảy ra lỗi, quá trình sẽ kết thúc ở trạng thái rejected.

Ví dụ: khi muốn lấy thông tin bài viết từ blog homiedev.com, chúng ta sẽ yêu cầu dữ liệu từ server bằng cách sử dụng một promise, server sẽ xử lý request và promise lúc này sẽ ở trạng thái pending. Khi dữ liệu trả về thành công, promise sẽ chuyển thành trạng thái fulfilled. Nếu có lỗi xảy ra, thì nó sẽ ở trạng thái rejected.

Sau đây chúng ta cùng xem cách tạo một promise nhé 😀.

Tạo Promise trong JavaScript

Để tạo một đối tượng promise, chúng ta sẽ sử dụng constructor Promise().

let

promise

=

new

Promise

(

function

(

resolve

,

reject

)

{

}

)

;

Constructor Promise() nhận một function làm đối số. function này có hai đối số là hai hàm resolve()reject().

Nếu promise trả về kết quả thành công, hàm resolve() được gọi. Nếu có lỗi xảy ra, hàm reject() được gọi.

Lý thuyết nhiều rồi 😋, bây giờ chúng ta cùng xem một ví dụ để dễ hiểu hơn nhé ^^:

let

promise

=

new

Promise

(

function

(

resolve

,

reject

)

{

setTimeout

(

(

)

=>

resolve

(

"done"

)

,

1000

)

;

}

)

;

Khi chạy đoạn code trên:

  1. function trong Promise sẽ được gọi tự động và ngay lập tức (khi sử dụng new Promise).
  2. function trong Promise nhận hai đối số: resolve và reject. Các hàm này được xác định trước bởi JavaScript engine, vì vậy chúng ta không cần tạo chúng.

Ở ví dụ trên, mình giả sử chúng ta thực hiện một công việc mất khoảng 1s, sau 1s xử lý, resolve("done") sẽ được thực thi. Điều này làm thay đổi trạng thái của promise:

  1. Lời hứa (promise) lúc này “đã được thực hiện”, trạng thái chuyển thành fulfilled.

new Promise()
Thực thi: resolve(“done”)
Chuyển trạng thái

state: “pending”
👉👉
state: “fulfilled”

result: undefined
👉👉
result: “done”

Nếu lời hứa (promise) của chúng ta bị từ chối (reject) thì sao ❔ chúng ta cùng đến với ví dụ:

let

promise

=

new

Promise

(

function

(

resolve

,

reject

)

{

setTimeout

(

(

)

=>

reject

(

new

Error

(

"Xảy ra lỗi rồi 😢!"

)

)

,

1000

)

;

}

)

;

Lúc này trạng thái promise sẽ chuyển thành:

new Promise()
Thực thi: reject(error)
Chuyển trạng thái

state: “pending”
👉👉
state: “rejected”

result: undefined
👉👉
result: Error: Xảy ra lỗi rồi 😢!

Tóm lại, chúng ta thực hiện một công việc (thường là một công việc cần thời gian) và sau đó gọi resolve hoặc reject để thay đổi trạng thái của promise.

Một lời hứa đã resolved hoặc rejected được gọi là “settled” (đã giải quyết), trái ngược với lời hứa ban đầu “pending”.

Các thuộc tính state và result của một object Promise là internal (bên trong Promise mới sử dụng được). Chúng ta không thể truy cập trực tiếp để sử dụng chúng. Để có thể truy cập thuộc tính của Promise, chúng ta có thể sử dụng các method .then, .catch, .finally.

then(), catch() trong JavaScript

Method then() trong JavaScript nhận hai đối số: các callback function cho trường hợp thành công và thất bại của promise.

Bạn có thể đọc bài viết về callback function tại đây: Callback Function trong JavaScript là gì? tại sao lại được sử dụng nhiều như vậy?.

Cú pháp của method then() là:

promiseObject

.

then

(

(

value

)

=>

{

}

,

(

reason

)

=>

{

}

,

)

;

Trong đó:

  1. Đối số đầu tiên của .then là một hàm chạy khi promise được resolved và nhận kết quả.
  2. Đối số thứ hai của .then là một hàm chạy khi promise bị rejected và nhận được lỗi.

Ví dụ:

Hiển thị kết quả nhận được từ promise đã resolved.

let

promise

=

new

Promise

(

function

(

resolve

,

reject

)

{

setTimeout

(

(

)

=>

resolve

(

"Thành công!"

)

,

1000

)

;

}

)

;

promise

.

then

(

result

=>

alert

(

result

)

,

error

=>

alert

(

error

)

)

;

Nếu quá trình promise xử lý bị lỗi, ví dụ:

let

promise

=

new

Promise

(

function

(

resolve

,

reject

)

{

setTimeout

(

(

)

=>

reject

(

new

Error

(

"Lỗi mất rồi 😢!"

)

)

,

1000

)

;

}

)

;

promise

.

then

(

result

=>

alert

(

result

)

,

error

=>

alert

(

error

)

)

;

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

let

promise

=

new

Promise

(

resolve

=>

{

setTimeout

(

(

)

=>

resolve

(

"Thành công!"

)

,

1000

)

;

}

)

;

promise

.

then

(

alert

)

;

Chúng ta có thể xử lý công việc từng phân đoạn bằng cách sử dụng nhiều .then() như sau:

let

countValue

=

new

Promise

(

function

(

resolve

,

reject

)

{

resolve

(

"Xử lý thành công!"

)

;

}

)

;

countValue

.

then

(

function

successValue

(

result

)

{

return

result

;

}

)

.

then

(

function

successValue1

(

result

)

{

return

result

+

' 😁'

;

}

)

.

then

(

function

successValue2

(

result

)

{

console

.

log

(

result

)

;

}

)

;

Nếu chúng ta chỉ quan tâm đến xử lí 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 method .catch(errorHandlingFunction):

let

promise

=

new

Promise

(

(

resolve

,

reject

)

=>

{

setTimeout

(

(

)

=>

reject

(

new

Error

(

"Lỗi mất rồi!"

)

)

,

1000

)

;

}

)

;

promise

.

catch

(

alert

)

;

Sử dụng .catch(f) cũng giống như .then (null, f), nó chỉ là một cách viết tắt (shorthand) 😁.

finally trong JavaScript

Trong promise cũng có finally giống như trong try {...} catch {...}

Các bạn có thể đọc bài viết về try {...} catch {...} tại: Try Catch Javascript là gì?.

Method finally() có thể hữu ích khi chúng ta muốn thực hiện một số xử lý sau khi promise đã được giải quyết xong (settled), bất kể kết quả của nó như thế nào.

Ví dụ. dừng các loading, đóng các kết nối không cần thiết, …

new

Promise

(

(

resolve

,

reject

)

=>

{

setTimeout

(

(

)

=>

resolve

(

"Đây là blog homiedev.com"

)

,

2000

)

;

}

)

.

finally

(

(

)

=>

alert

(

"Promise ready"

)

)

.

then

(

result

=>

alert

(

result

)

)

;

Tóm lại, đây là những lưu ý về finally các bạn cần nắm ^^:

  1. finally không nhận được kết quả của hàm xử lý trước (nó không có đối số). Thay vào đó, kết quả này sẽ được chuyển tới hàm xử lý phù hợp tiếp theo.
  2. Nếu finally return một cái gì đó, nó sẽ bị bỏ qua.
  3. Khi finally throw một lỗi, thì quá trình thực thi sẽ chuyển đến hàm xử lý lỗi gần nó nhất.

Như vậy là chúng ta đã tìm hiểu cơ bản về promise trong JavaScript. Những vấn đề liên quan khác chúng ta sẽ tìm hiểu trong các bài viết sau nhé ^^.

Hi vọng bài viết giúp ích cho các bạn. Nếu có thắc mắc chúng ta cùng thảo luận bên dưới phần bình luận nhé 😉.