0
0
Lập trình
Harry Tran
Harry Tran106580903228332612117

Hướng Dẫn Tự Xây Dựng Promise Trong JavaScript Đúng Chuẩn Promises/A+

Đăng vào 4 ngày trước

• 3 phút đọc

Hướng Dẫn Tự Xây Dựng Promise Trong JavaScript Đúng Chuẩn Promises/A+

Trong bài viết hôm nay, mình sẽ chia sẻ quá trình tự xây dựng một Promise trong JavaScript từ đầu, theo chuẩn Promises/A+. Đây không chỉ là một bài tập kiểm tra khả năng lập trình của bản thân mà còn là cơ hội để chia sẻ những gì mình học được tới các bạn đam mê lập trình. Hãy cùng bắt đầu nào!

Tạo Class Promise Đầu Tiên

Chúng ta sẽ gọi Promise tự tạo này là NotNow vì các tên hấp dẫn như will, future, hay later đã có nhiều package khác sử dụng. Để bắt đầu, hãy định nghĩa một số trạng thái cùng class NotNow:

javascript Copy
const PENDING = "pending";
const FULFILLED = "fulfilled";

class NotNow {
  #state = PENDING;
  #onFulfilleds = [];
  #value;

  constructor(fn) {
    fn(this.#fulfill.bind(this));
  }

  #fulfill(value) {
    this.#state = FULFILLED;
    this.#value = value;
    this.#onFulfilleds.forEach((fn) => fn(value));
  }

  then(onFulfilled) {
    this.#addOnFulfilled(onFulfilled);
  }

  #addOnFulfilled(onFulfilled) {
    if (this.#state === PENDING) {
      this.#onFulfilleds.push(onFulfilled);
    } else if (this.#state === FULFILLED) {
      onFulfilled(this.#value);
    }
  }
}

Trong constructor, chúng ta sẽ thực thi hàm được truyền vào, với phương thức #fulfill hoạt động như một callback để trả giá trị về. Hàm #fulfill sẽ lưu lại giá trị trả về và kích hoạt tất cả callback với giá trị đã lưu.

Kiểm Tra Promise Đơn Giản

Hãy kiểm tra NotNow với đoạn mã dưới:

javascript Copy
const notNow = new NotNow((fulfill) => {
  setTimeout(() => fulfill(2), 2000);
});
notNow.then((value) => console.log(`callback 1, fulfilled with ${value}`));
notNow.then((value) => console.log(`callback 2, fulfilled with ${value}`));

Sau 2 giây, kết quả sẽ là:

Copy
callback 1, fulfilled with 2
callback 2, fulfilled with 2

Thực Thi Callback Một Cách Bất Đồng Bộ

Để đảm bảo tính nhất quán, các callback sẽ được thực thi một cách bất đồng bộ. Do đó, chúng ta sẽ điều chỉnh lại hàm #fulfill để sử dụng queueMicrotask như sau:

javascript Copy
queueMicrotask(() => this.#onFulfilleds.forEach((fn) => fn(value)));

Tạo Promise Mới Từ Callback

Mỗi lần khi thêm callback vào, chúng ta thực chất đang tạo ra một Promise mới. Để thực hiện điều này, chúng ta sẽ điều chỉnh phương thức then để trả về một Promise mới mỗi khi nhận được kết quả. Dưới đây là đoạn mã đã được cập nhật:

javascript Copy
class NotNow {
  //... 
  then(onFulfilled) {
    return new Promise((nextFulfill) => {
      this.#addOnFulfilled((value) => {
        const nextValue = onFulfilled(value);
        nextFulfill(nextValue);
      });
    });
  }
}

Kiểm Tra Ràng Buộc Promise

Chúng ta có thể nối tiếp nhiều phương thức then, và các giá trị trả về sẽ được xử lý liên tục:

javascript Copy
new NotNow((fulfill) => {
  setTimeout(() => fulfill(2), 2000);
})
  .then((value) => value * 2)
  .then((value) => console.log(value));

Khi Promise nhận được giá trị 2, sau đó giá trị cuối cùng in ra sẽ là 4.

Xử Lý Promise Lồng

Một đặc điểm thú vị của Promise là nếu bạn trả về một Promise từ một Promise khác, nó sẽ tự động nhận giá trị. Đây là cách chúng ta kiểm thử tính năng này:

javascript Copy
const a = new Promise((fulfill) => fulfill(2));
const b = new Promise((fulfill) => fulfill(a));
b.then((value) => console.log(value));

Kết quả vẫn là 2, cho thấy khái niệm này hoạt động chính xác.

Kiểm Tra Với Async/Await

Class NotNow cũng hỗ trợ async/await một cách hoàn hảo. Bạn có thể dùng nó như sau:

javascript Copy
const a = await new NotNow((fulfill) => {
  setTimeout(() => fulfill(5), 2000);
});
console.log(a);

Kết Luận

Trong bài viết này, mình đã giới thiệu cách xây dựng một Promise từ đầu theo chuẩn Promises/A+. Mặc dù bài viết chưa đề cập đến xử lý lỗi và một số phương thức bổ sung như all, allSettled, any, race, nhưng hy vọng bạn sẽ thấy nó hữu ích. Nếu bạn có bất kỳ câu hỏi hay ý kiến nào, hãy để lại ý kiến trong phần bình luận nhé!

source: viblo

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào