Giải quyết các vấn đề hiệu năng và trải nghiệm khi xem trước tệp tin: Excel lớn, OFD và PDF

1. Xử lý Excel dung lượng lớn: Tối ưu hóa việc quét dữ liệu trước khi hiển thị

Khi xử lý các tệp Excel có hàng trăm nghìn dòng, việc áp dụng Virtual Scrolling (cuộn ảo) chỉ giải quyết được vấn đề về số lượng DOM. Tuy nhiên, trước khi Render bản ghi đầu tiên, hệ thống thường gặp hiện tượng treo do phải tính toán độ rộng cột tự động dựa trên toàn bộ nội dung tệp.

Giải pháp hiệu quả là thiết lập một hạn mức lấy mẫu (sampling) và phân phối các mẫu này qua nhiều phân đoạn dữ liệu khác nhau thay vì quét toàn bộ:

const CELL_SAMPLING_LIMIT = 100000;
const SEGMENT_COUNT = 8;
const MAX_ROWS_PER_SEGMENT = 128;

// Tính toán số dòng cần lấy mẫu cho mỗi phân đoạn
const rowsToScan = Math.max(1, Math.min(
  MAX_ROWS_PER_SEGMENT,
  Math.floor(CELL_SAMPLING_LIMIT / totalColumns / SEGMENT_COUNT)
));

Với các tệp nhỏ, chúng ta vẫn đo lường toàn bộ. Với tệp lớn, thuật toán sẽ lấy mẫu tại các vị trí đầu, giữa và cuối tệp để tính toán độ rộng cột đại diện. Điều này giúp loại bỏ các "Long Task" gây nghẽn Main Thread, đồng thời đảm bảo độ rộng cột vẫn chính xác một cách tương đối.

2. Khắc phục lỗi nhấp nháy (Flickering) trên tệp OFD

Vấn đề xảy ra khi các phần tử OFD chưa có thuộc tính transform lúc mới chèn vào DOM. Khi bố cục hoàn tất và JavaScript thiết lập giá trị căn giữa hoặc thu phóng, nếu CSS đang lắng nghe thay đổi của transform, trình duyệt sẽ thực hiện một hiệu ứng chuyển cảnh ngoài ý muốn.

Để xử lý, chúng ta chỉ kích hoạt hiệu ứng chuyển cảnh sau khi quá trình khởi tạo trạng thái ban đầu đã hoàn tất:

/* Trạng thái mặc định không có transition */
.ofd-content-page { 
  transition: none; 
}

/* Chỉ kích hoạt khi đã sẵn sàng */
.ofd-content-page.is-initialized {
  transition: transform 150ms cubic-bezier(0.4, 0, 0.2, 1);
}

@media (prefers-reduced-motion: reduce) {
  .ofd-content-page.is-initialized { 
    transition: none; 
  }
}

Việc quản lý Class is-initialized thông qua vòng đời của Component đảm bảo rằng lần hiển thị đầu tiên luôn tức thời, trong khi các thao tác thu phóng sau đó của người dùng vẫn mượt mà.

3. Neo vị trí cuộn khi phóng to/thu nhỏ PDF

Khi thay đổi tỷ lệ hiển thị (Zoom), tổng chiều cao của tài liệu PDF thay đổi, dẫn đến giá trị scrollTop cũ không còn trỏ đúng vị trí mà người dùng đang đọc. Để giải quyết, chúng ta cần lưu lại số trang hiện tại và tỷ lệ phần trăm vị trí trong trang đó trước khi thực hiện Zoom.

interface ScrollAnchor {
  pageIndex: number;
  relativeOffset: number; // Tỷ lệ từ 0 đến 1
}

const savePosition = (): ScrollAnchor => {
  return {
    pageIndex: currentVisiblePage,
    relativeOffset: (container.scrollTop - currentPageOffset) / currentPageHeight
  };
};

const restorePosition = (anchor: ScrollAnchor) => {
  const newScrollTop = newPageOffset + (anchor.relativeOffset * newPageHeight);
  container.scrollTop = newScrollTop;
};

Trong thực tế, cần lưu ý hai điểm quan trọng: Hủy các tác vụ khôi phục vị trí cũ nếu người dùng thực hiện thao tác Zoom liên tục, và ngừng tự động cuộn nếu phát hiện người dùng chủ động tương tác với thanh cuộn trong quá trình render.

4. Danh sách kiểm tra (Checklist) khi nghiệm thu

  • Kiểm tra hiệu năng với các tệp có kích thước và số trang cực đại.
  • Xác minh hành vi trên nhiều trình duyệt khác nhau để đảm bảo tính nhất quán của API Scroll.
  • Giám sát tài nguyên hệ thống (Memory, CPU) để phát hiện rò rỉ bộ nhớ khi chuyển đổi giữa các tệp.
  • Kiểm tra trạng thái Component qua các chu kỳ: Khởi tạo lần đầu -> Chuyển đổi tệp -> Render lại.
  • Đảm bảo các lỗi trên Console được xử lý triệt để, không ảnh hưởng đến luồng thực thi chính.

5. Phạm vi ứng dụng

Việc xem trước tệp tin trực tiếp trên trình duyệt là giải pháp tối ưu cho nhu cầu đọc nhanh. Tuy nhiên, đối với các nhu cầu chuyên sâu như chỉnh sửa tài liệu, xử lý tệp CAD phức tạp hoặc các tệp Excel có macro nặng, giải pháp chuyển đổi phía Server (Server-side rendering) hoặc ứng dụng chuyên dụng vẫn là sự lựa chọn an toàn hơn. Trình xem trước nên tập trung vào tốc độ phản hồi và độ chính xác về hiển thị nội dung tĩnh.

Thẻ: frontend file-preview Performance-Optimization JavaScript css

Đăng vào ngày 22 tháng 10 lúc 16:58