Promise Memoization

627

Bài viết được sự cho phép của tác giả Lưu Bình An

Chúng ta sẽ hiện thực caching với promise bằng cách dùng Promise Memoization

  6 lý do Async/Await của Javascript đánh bại Promises
  9 câu hỏi lắt léo về Promise

Ví dụ gọi một API để lấy thông tin của một userId

const getUserById = async (userId: string): Promise<User> => {
  const user = await request.get(`https://users-service/${userId}`);
  return user;
};

Nếu users-service hơi chậm, việc lưu lại giá trị trước đó đã get được là một ý tưởng thường thấy

const usersCache = new Map<string, User>();

const getUserById = async (userId: string): Promise<User> => {
  if (!usersCache.has(userId)) {
    const user = await request.get(`https://users-service/${userId}`);
    usersCache.set(userId, user);
  }

  return usersCache.get(userId);
};

Chúng ta lưu giá trị đó xuống in-memory (bộ nhớ RAM ấy), cách này cũng ok nhưng khá amater.

Nếu chúng ta không cache result trả về từ await mà cache luôn cái Promise?

const userPromisesCache = new Map<string, Promise<User>>();

const getUserById = (userId: string): Promise<User> => {
  if (!userPromisesCache.has(userId)) {
    const userPromise = request.get(`https://users-service/v1/${userId}`);
    userPromisesCache.set(userId, userPromise);
  }

  return userPromisesCache.get(userId)!;
};

Nó cũng na ná như ở trên nhưng chúng ta không còn await vào câu request, chúng ta cũng không cần dùng async function. Nếu bạn cảm thấy hơi hại não chổ này, thì nên làm thử cái demo nhỏ nhỏ này

Cách làm này có một cái tên khá ghê là Singleton Promise – chỉ dùng một promise duy nhất. Bởi vì chúng ta sẽ dùng cùng một Promise với cùng một userId nên khi có một race condition như cách viết bên dưới

await Promise.all([
    getUserById('user1'),
  	getUserById('user1')
])

chúng ta không gặp bất cứ vấn đề gì.

Đó là khi bạn có tinh thần em yêu khoa học, còn đơn giản nhất, đỡ tốn công nhất, bạn có thể dùng những lodash.memoize

import _ from 'lodash';

const getUserById = _.memoize(async (userId: string): Promise<User> => {
  const user = await request.get(`https://users-service/${userId}`);
  return user;
});

Advanced Promise Patterns: Promise Memoization

Bài viết gốc được đăng tải tại vuilaptrinh.com

Có thể bạn quan tâm:

Xem thêm Việc làm Developer hấp dẫn trên TopDev