Tìm hiểu về Promise, cách sử dụng và một số lưu ý!

Phụ lục
tim-hieu-ve-promise-cach-su-dung-va-mot-so-luu-y

Vấn đề
Sẽ thực sự bị bỏ sót dù không nói về Promise trong JavaScript . Thực tế, các bài viết về Promise đã có rất nhiều người viết, bạn đọc có thể tìm thấy chúng bằng Google hoặc bắt gặp lại trong một hội nhóm có liên quan đến trình cài đặt nào đó. Nhưng vì Promise là một kiến ​​thức quan trọng và mỗi người lại có cách truyền đạt khác nhau nên tôi vẫn quyết định viết bài này.

Thời kỳ đầu học JavaScript mới, Promise là thứ gây nhầm lẫn nhiều nhất. Cứ nghĩ mình hiểu và biết cách sử dụng rồi nhưng trên thực tế, vẫn còn nhiều cú trượt dài đau rồi tự rút ra bài học cho mình. Tôi đọc nhiều bài nói về Promise cả tiếng Anh lẫn tiếng Việt, tăng dần mọi thứ thứ như tích tiểu thành đại, giúp cho mình hiểu và sử dụng thế nào cho đúng đắn.

Bài viết này sẽ không đi sâu vào khái niệm của Promise mà chỉ đi qua một vài ý lưu trữ và những điều có thể có lẫn lộn. Qua đó giúp bạn đọc hình ảnh và tránh một số lỗi trong quá trình viết mã của mình.

Hứa là gì?

Promise là một đại diện tượng trưng cho một kết quả trả về trong tương lai. Hay nói cách khác, Promise đại diện cho một kết quả của hàm không đồng bộ.

Một Promise bao gồm 3 trạng thái tương ứng với 3 kết quả của hàm bất đồng bộ.

  • pending là trạng thái ban đầu, đang chờ kết quả.
  • fulfilled là quá trình xử lý trạng thái thành công, có kết quả trả về.
  • rejected là trạng thái thất bại, có thể đính kèm chi tiết lỗi.

Về bản chất, Promise là đại diện cho kết quả trả về trong tương lai. Ở ví dụ trên, chúng tôi hoàn toàn không cần thiết phải tạo một Promise để xử lý, vì tất cả các hoạt động bên trong hàm  fn đều là đồng bộ. Vậy thì như thế nào là bất đồng bộ cũng như nên tạo ra Promise khi nào?

Thế nào là bất đồng bộ chức năng? Tôi đã nhắc đến nhiều bài viết. Một số tác vụ I/O được cung cấp bởi hàm bất đồng bộ, vì chúng không thể trả về kết quả ngay lập tức mà phụ thuộc vào nhiều yếu tố bên ngoài như phần cứng tốc độ, tốc độ mạng… Nếu chờ các hoạt động này có thể xảy ra lãng phí thời gian hoặc gây ra tình trạng tắc nghẽn nghiêm trọng.

Lấy ví dụ về hành vi thực hiện một truy vấn GET đến địa chỉ  https://example.com,  lúc này công việc xử lý không đơn thuần phụ thuộc vào tốc độ của CPU nữa mà phụ thuộc vào tốc độ mạng của bạn. Mạng càng nhanh, bạn sẽ nhanh chóng có kết quả và ngược lại. Trong JavaScript, chúng tôi có hàm  fetch để gửi yêu cầu và hàm này bất đồng bộ, không trả về một Promise.

fetch('https://example.com');

Để xử lý kết quả của Promise, chúng tôi có  then và  catch so sánh hai trường hợp thành công và thất bại.

fetch('https://example.com')
    .then(res => console.log(res))
    .catch(err => console.log(err));

If after a xử lý thời gian,  fetch có trạng thái  fulfilled, hàm trong  then sẽ được kích hoạt, ngược lại,  fetch có trạng thái  rejected, ngay lập tức hàm trong  catch được thực thi.

Thực ra câu hỏi này nhằm kiểm tra kiến thức của bạn về hành vi bất đồng bộ trong JavaScript. Kết quả in ra là 1, 2, 3 chứ không phải là 1, 3, 2. Điều này xảy ra là do cơ chế xử lý bất đồng bộ, vì kết quả của hành vi bất đồng bộ sẽ được trả về trong tương lai cho nên JavaScript sẽ nghĩ rằng: “OK, hàm bất đồng bộ này chưa có kết quả ngay được, để đó đã, xử lý tiếp các lệnh bên dưới, khi nào hết sạch thì quay lại xem nó có kết quả chưa”. Bạn đọc có thể tham khảo thêm các bài viết về cơ chế xử lý bất đồng bộ tại Lập trình bất đồng bộ là gì? Tại sao JavaScript là ngôn ngữ lập trình bất đồng bộ?.

Trong Promise có một số hàm static hữu dụng trong nhiều trường hợp như: allallSettledany và race.

Promise.all nhận vào một mảng các Promise, nó cũng trả về một Promise và có trạng thái fulfilled khi tất cả Promise trong mảng đều thành công, ngược lại, nó có trạng thái rejected khi chỉ cần 1 Promise trong mảng bị thất bại.

Promise.allSettled cũng tương tự như Promise.all chỉ có điều nó luôn trả về tất cả kết quả của Promise trong mảng cho dù là thành công hay thất bại. Cả hai Promise.all và Promise.allSettled hữu ích trong trường hợp bạn cần chạy nhiều hàm bất đồng bộ ngay lập tức mà không quan trọng thứ tự kết quả.

Trong khi Promise.race trả về kết quả của Promise được giải quyết nhanh nhất trong mảng, không kể là thành công hay thất bại, thì Promise.any lại trả về kết quả thành công của Promise có trạng thái fulfilled đầu tiên trong mảng. race và any phù hợp trong các trường hợp bạn có nhiều Promise thực hiện hành động giống nhau và cần một trường hợp dự phòng giữa các kết quả đó.

Promise thay thế “callback hell”

Thật ngạc nhiên khi biết rằng trước kia JS không có Promise, đúng vậy bạn không nghe nhầm đâu, điều đó khiến cho Node.js cũng không có Promise trong những ngày đầu, và đó cũng chính là hối hận lớn nhất mà cha đẻ Node.js phải thốt ra.

Mọi tác vụ bất đồng bộ trước kia được xử lý qua callback, chúng ta cần xác định một hàm callback để xử lý kết quả trong tương lai.

return và return await

Thi thoảng, bạn sẽ bắt gặp đoạn mã trông giống như thế này ở đâu đó.

async function fn() {
    …
    return await asyncFn();
}

Hàm fn trên đang trả về một await của hàm bất đồng bộ asyncFn. Có lẽ tác giả đang dụng ý fn trả về một kết quả của asyncFn luôn, vì await là đang chờ kết quả của hàm bất đồng bộ mà, từ đó biến fn thành hàm đồng bộ, hay nói cách khác là fn “không” trả về một Promise nữa.

Nhưng rất tiếc đó là một nhầm lẫn tai hại, về bản chất await chỉ được sử dụng ở top-level, hoặc trong một hàm có khai báo async, mà đã là async thì hàm đó chắc chắn trả về một Promise. Do đó fn luôn luôn trả về Promise. Vậy tại sao lại return await asyncFn()?

Chỉ cần return asyncFn() thôi có thể tiết kiệm được một chút thời gian gõ phím của bạn, nó không có khác biệt gì đáng kể so với return await asyncFn(). Thay đổi lớn chỉ xảy ra khi xuất hiện try…catch ở return.

Hàm đầu tiên, rejectionWithReturnAwait đang cố return await và khi Promise này trả ra lỗi, catch nhanh chóng bắt lỗi đó và xử lý lệnh return 'Saved!'. Nghĩa là hàm này trả về một Promise chứa chuỗi ‘Saved’.

Ngược lại, rejectionWithReturn vì không có await nên hàm đang cố gắng đẩy ra một lỗi Promise.reject(new Error())catch lúc này không bao giờ được thực thi nữa.




Devwork

Devwork là Nền tảng TUYỂN DỤNG IT CẤP TỐC với mô hình kết nối Nhà tuyển dụng với mạng lưới hơn 30.000 headhunter tuyển dụng ở khắp mọi nơi.Với hơn 1800 doanh nghiệp IT tin dùng Devwork để :

  • Tối ưu chi phí
  • Tiết kiệm thời gian
  • Tăng tốc tuyển dụng tối đa
  • Đăng ký ngay Devwork trong hôm nay để tuyển dụng những tài năng ưu tú nhất.

    Tag Cloud:

    Tác giả: quyenntt

    Link chia sẻ

    Bình luận

    Việc làm tại Devwork

    khám phá các cơ hội việc làm tốt nhất tại Devwork Xem thêm

    Bài viết liên quan

    Danh sách bài viết liên quan có thể bạn sẽ thích Xem thêm
    kiem-tra-toc-do-mang-wifi

    Kiểm tra tốc độ mạng Wifi: Bí quyết tối ưu trải nghiệm Internet

    07:06 02/07/2025

    Internet hiện diện như một phần không thể thiếu trong cuộc sống hiện đại của chúng ta. Từ làm việc, học tập, giải trí cho đến liên lạc, mọi thứ đều cần đến kết nối mạng ổn định và nhanh chóng. Nhưng có khi nào bạn tự hỏi, liệu tốc độ mạng Wifi nhà mình có đang "chạy" đúng như những gì bạn trả tiền không?...

    Package là gì? Cách sử dụng & quản lý package hiệu quả 

    06:57 01/07/2025

    Dù bạn đang học Python, JavaScript hay bất kỳ ngôn ngữ nào khác, package là một khái niệm bạn sẽ gặp thường xuyên. Nhưng package là gì? Vì sao mọi dự án phần mềm hiện đại đều cần đến chúng? Và làm sao để sử dụng package đúng cách? Bài viết này sẽ giúp bạn làm rõ tất cả những điều quan trọng về package trong lập trình.

    package-la-gi

    [A-Z] ELK là gì? Hướng dẫn triển khai ELK STACK cơ bản

    06:52 01/07/2025

    Bạn đang tìm hiểu ELK là gì và cách triển khai bộ công cụ này để phân tích log, giám sát hệ thống? Trong bài viết sau, Devwork sẽ cùng bạn khám phá từ khái niệm cơ bản đến hướng dẫn triển khai ELK Stack đơn giản nhất cho người mới bắt đầu, giúp bạn nhanh chóng làm chủ công cụ mạnh mẽ này.

    dinh-nghia-elk-la-gi

    Giải mã IOC là gì? Cách nhận diện và sử dụng chỉ số xâm nhập hiệu quả

    06:45 01/07/2025

    Các cuộc tấn công mạng thường để lại dấu vết. Những dấu vết ấy, từ file hash lạ, địa chỉ IP bất thường đến các hành vi sai lệch chính là IOC. Vậy IOC là gì, có mấy loại và làm thế nào để tận dụng IOC giúp hệ thống an toàn hơn? Bài viết này sẽ giải đáp tất cả những thắc mắc của bạn.

    giai-ma-ioc-la-gi
    database-administrator-la-gi

    Database Administrator là gì? Ai phù hợp với nghề quản trị cơ sở dữ liệu? 

    07:11 26/06/2025

    Database Administrator (DBA) là gì và tại sao vai trò này lại đang trở thành một trong những nghề nghiệp được săn đón nhất trong lĩnh vực công nghệ thông tin? Devwork giới thiệu đến bạn tổng quan về nghề nghiệp đầy tiềm năng này, từ định nghĩa, trách nhiệm, lộ trình phát triển đến cơ hội việc làm và mức lương hấp dẫn của một DBA.

    bo-phan-qc-la-gi

    QC là gì? 5 điều phải biết trước khi theo nghề “kiểm soát chất lượng"

    06:59 26/06/2025

    Bạn đang tìm hiểu về nghề QC? Bạn muốn biết QC là gì, công việc của một nhân viên QC ra sao, và liệu đây có phải là con đường sự nghiệp phù hợp với mình? Bài viết này sẽ cung cấp cho bạn cái nhìn toàn diện về vị trí QC, từ định nghĩa, vai trò, công việc, đến cơ hội phát triển trong ngành.