Ứng dụng nhiều trang nhanh hơn với luồng

Ngày nay, trang web (hoặc ứng dụng web nếu bạn muốn) có xu hướng sử dụng một trong hai lược đồ điều hướng:

  • Giao thức điều hướng mà trình duyệt cung cấp theo mặc định – tức là bạn nhập một URL vào thanh địa chỉ của trình duyệt và một yêu cầu điều hướng sẽ trả về một tài liệu dưới dạng phản hồi. Sau đó, bạn nhấp vào một đường liên kết. Thao tác này sẽ tải tài liệu hiện tại cho một tài liệu khác, quảng cáo vô hạn.
  • Mẫu ứng dụng trang đơn, bao gồm yêu cầu điều hướng ban đầu để tải shell ứng dụng và dựa vào JavaScript để điền giao diện ứng dụng bằng mã đánh dấu do ứng dụng hiển thị với nội dung từ API phụ trợ cho mỗi "điều hướng".

Lợi ích của mỗi phương pháp đã được người đề xuất quảng cáo:

  • Giao thức điều hướng mà trình duyệt cung cấp theo mặc định có tính linh hoạt, vì các tuyến không yêu cầu JavaScript mới có thể truy cập được. Việc máy khách hiển thị mã đánh dấu bằng JavaScript cũng có thể là một quá trình có thể tốn kém, nghĩa là các thiết bị cấp thấp có thể gặp phải trường hợp nội dung bị trễ do thiết bị bị chặn xử lý các tập lệnh cung cấp nội dung.
  • Mặt khác, Ứng dụng trang đơn (SPA) có thể cho phép điều hướng nhanh hơn sau lần tải ban đầu. Thay vì dựa vào trình duyệt để tải một tài liệu hoàn toàn mới (và lặp lại thao tác này cho mỗi lần điều hướng), họ có thể cung cấp một tài liệu nhanh hơn, "giống với ứng dụng" hơn trải nghiệm người dùng—ngay cả khi cần phải có JavaScript để hoạt động.

Trong bài đăng này, chúng ta sẽ nói về phương pháp thứ ba giúp tạo ra sự cân bằng giữa hai cách tiếp cận được mô tả ở trên: dựa vào service worker để lưu trước trong bộ nhớ đệm các thành phần phổ biến của trang web (chẳng hạn như đánh dấu đầu trang và chân trang) và sử dụng luồng để cung cấp phản hồi HTML cho khách hàng nhanh nhất có thể, trong khi vẫn sử dụng giao thức điều hướng mặc định của trình duyệt.

Tại sao nên truyền trực tuyến phản hồi HTML trong trình chạy dịch vụ?

Phát trực tuyến là một tính năng mà trình duyệt web của bạn đã thực hiện khi đưa ra yêu cầu. Điều này cực kỳ quan trọng trong ngữ cảnh của các yêu cầu điều hướng, vì nó đảm bảo trình duyệt không bị chặn khi đang chờ toàn bộ phản hồi trước khi có thể bắt đầu phân tích cú pháp đánh dấu tài liệu và hiển thị một trang.

Sơ đồ mô tả HTML không truyền trực tuyến so với HTML phát trực tuyến. Trong trường hợp trước, toàn bộ tải trọng đánh dấu sẽ không được xử lý cho đến khi đến nơi. Sau đó, mã đánh dấu được xử lý tăng dần khi đến các đoạn dữ liệu từ mạng.

Đối với trình chạy dịch vụ, tính năng truyền trực tuyến sẽ hơi khác vì sử dụng API Luồng JavaScript. Nhiệm vụ quan trọng nhất mà một trình chạy dịch vụ phải thực hiện là chặn và phản hồi các yêu cầu, bao gồm cả các yêu cầu điều hướng.

Các yêu cầu này có thể tương tác với bộ nhớ đệm theo một số cách, tuy nhiên, một mẫu lưu vào bộ nhớ đệm phổ biến dành cho mã đánh dấu là ưu tiên sử dụng phản hồi từ mạng trước, còn quay lại bộ nhớ đệm nếu có bản sao cũ hơn – và có thể cung cấp một phản hồi dự phòng chung nếu không có phản hồi hữu dụng trong bộ nhớ đệm.

Đây là mẫu đánh dấu đã được thử nghiệm theo thời gian và hoạt động hiệu quả, nhưng tuy giúp tăng độ tin cậy khi truy cập khi không có mạng, nhưng lại không mang lại lợi thế vốn có về hiệu suất cho những yêu cầu điều hướng dựa vào chiến lược trước hết là mạng hoặc chỉ dựa vào mạng. Đó là lúc phát trực tiếp hoạt động. Chúng ta sẽ khám phá cách sử dụng mô-đun workbox-streams dựa trên API Luồng trong trình chạy dịch vụ Workbox của bạn để tăng tốc các yêu cầu điều hướng trên trang web nhiều trang của bạn.

Chia nhỏ một trang web thông thường

Theo cấu trúc, trang web thường có các phần tử phổ biến tồn tại trên mỗi trang. Cách sắp xếp điển hình của các phần tử trang thường có dạng như sau:

  • Tiêu đề.
  • Nội dung.
  • Chân trang.

Lấy web.dev làm ví dụ, bảng chi tiết về các yếu tố phổ biến sẽ có dạng như sau:

Bảng phân tích các yếu tố phổ biến trên trang web web.dev. Các khu vực chung được khoanh vùng được đánh dấu là "đầu trang", "nội dung" và "chân trang".

Mục tiêu của việc xác định các phần của một trang là để chúng tôi xác định những nội dung có thể được lưu trước trong bộ nhớ đệm và truy xuất mà không cần vào mạng—cụ thể là đánh dấu tiêu đề và chân trang chung cho tất cả các trang—và phần của trang mà chúng tôi sẽ luôn truy cập mạng trước tiên—nội dung trong trường hợp này.

Khi biết cách phân đoạn các phần của một trang và xác định các phần tử phổ biến, chúng ta có thể viết một trình chạy dịch vụ luôn truy xuất thẻ đánh dấu tiêu đề và chân trang ngay lập tức từ bộ nhớ đệm trong khi chỉ yêu cầu nội dung từ mạng.

Sau đó, bằng cách sử dụng API Luồng thông qua workbox-streams, chúng ta có thể ghép tất cả các phần này lại với nhau và phản hồi các yêu cầu điều hướng ngay lập tức – trong khi vẫn yêu cầu số lượng mã đánh dấu tối thiểu cần thiết từ mạng.

Xây dựng trình thực thi dịch vụ xem trực tuyến

Có rất nhiều phần di chuyển khi truyền trực tuyến nội dung từng phần trong một trình chạy dịch vụ, nhưng mỗi bước của quy trình sẽ được khám phá chi tiết trong quá trình bạn tiếp tục, bắt đầu với cách cấu trúc trang web của bạn.

Phân đoạn trang web của bạn thành các phần

Trước khi có thể viết một trình chạy dịch vụ phát trực tuyến, bạn cần làm 3 việc:

  1. Tạo một tệp chỉ chứa mã đánh dấu tiêu đề của trang web.
  2. Tạo một tệp chỉ chứa mã đánh dấu chân trang của trang web.
  3. Trích xuất nội dung chính của mỗi trang vào một tệp riêng hoặc thiết lập phụ trợ để chỉ phân phát nội dung trang theo điều kiện dựa trên tiêu đề của yêu cầu HTTP.

Như bạn dự kiến, bước cuối cùng là khó nhất, đặc biệt khi trang web của bạn tĩnh. Trong trường hợp đó, bạn cần phải tạo hai phiên bản của mỗi trang: một phiên bản sẽ chứa mã đánh dấu trang đầy đủ, trong khi phiên bản còn lại sẽ chỉ chứa nội dung.

Soạn thảo một trình chạy dịch vụ truyền trực tuyến

Nếu chưa cài đặt mô-đun workbox-streams, bạn cần cài đặt cùng với bất kỳ mô-đun Workbox nào mà bạn hiện đã cài đặt. Trong ví dụ cụ thể này, việc này bao gồm các gói sau:

npm i workbox-navigation-preload workbox-strategies workbox-routing workbox-precaching workbox-streams --save

Từ đây, bước tiếp theo là tạo trình chạy dịch vụ mới và lưu trước các phần đầu trang và chân trang của bạn vào bộ nhớ đệm.

Đang chuẩn bị một phần dữ liệu lưu vào bộ nhớ đệm

Việc đầu tiên bạn cần làm là tạo một trình chạy dịch vụ trong thư mục gốc của dự án có tên là sw.js (hoặc bất kỳ tên tệp nào bạn muốn). Trong đó, bạn sẽ bắt đầu với những nội dung sau:

// sw.js
import * as navigationPreload from 'workbox-navigation-preload';
import {NetworkFirst} from 'workbox-strategies';
import {registerRoute} from 'workbox-routing';
import {matchPrecache, precacheAndRoute} from 'workbox-precaching';
import {strategy as composeStrategies} from 'workbox-streams';

// Enable navigation preload for supporting browsers
navigationPreload.enable();

// Precache partials and some static assets
// using the InjectManifest method.
precacheAndRoute([
  // The header partial:
  {
    url: '/partial-header.php',
    revision: __PARTIAL_HEADER_HASH__
  },
  // The footer partial:
  {
    url: '/partial-footer.php',
    revision: __PARTIAL_FOOTER_HASH__
  },
  // The offline fallback:
  {
    url: '/offline.php',
    revision: __OFFLINE_FALLBACK_HASH__
  },
  ...self.__WB_MANIFEST
]);

// To be continued...

Mã này thực hiện một số việc:

  1. Bật tính năng tải trước điều hướng cho các trình duyệt hỗ trợ tính năng này.
  2. Lưu trước thẻ đánh dấu đầu trang và chân trang trong bộ nhớ đệm. Điều này có nghĩa là đánh dấu đầu trang và chân trang cho mỗi trang sẽ được truy xuất ngay lập tức, vì nó sẽ không bị mạng lưới chặn.
  3. Lưu trước các tài sản tĩnh trong bộ nhớ đệm trong phần giữ chỗ __WB_MANIFEST có sử dụng phương thức injectManifest.

Hiện câu trả lời theo thời gian thực

Để trình chạy dịch vụ của bạn truyền trực tuyến các phản hồi nối là phần lớn nhất trong toàn bộ nỗ lực này. Mặc dù vậy, Workbox và workbox-streams của Work giúp cho việc này trở nên ngắn gọn hơn nhiều so với khi bạn phải tự thực hiện tất cả những việc này:

// sw.js
import * as navigationPreload from 'workbox-navigation-preload';
import {NetworkFirst} from 'workbox-strategies';
import {registerRoute} from 'workbox-routing';
import {matchPrecache, precacheAndRoute} from 'workbox-precaching';
import {strategy as composeStrategies} from 'workbox-streams';

// ...
// Prior navigation preload and precaching code omitted...
// ...

// The strategy for retrieving content partials from the network:
const contentStrategy = new NetworkFirst({
  cacheName: 'content',
  plugins: [
    {
      // NOTE: This callback will never be run if navigation
      // preload is not supported, because the navigation
      // request is dispatched while the service worker is
      // booting up. This callback will only run if navigation
      // preload is _not_ supported.
      requestWillFetch: ({request}) => {
        const headers = new Headers();

        // If the browser doesn't support navigation preload, we need to
        // send a custom `X-Content-Mode` header for the back end to use
        // instead of the `Service-Worker-Navigation-Preload` header.
        headers.append('X-Content-Mode', 'partial');

        // Send the request with the new headers.
        // Note: if you're using a static site generator to generate
        // both full pages and content partials rather than a back end
        // (as this example assumes), you'll need to point to a new URL.
        return new Request(request.url, {
          method: 'GET',
          headers
        });
      },
      // What to do if the request fails.
      handlerDidError: async ({request}) => {
        return await matchPrecache('/offline.php');
      }
    }
  ]
});

// Concatenates precached partials with the content partial
// obtained from the network (or its fallback response).
const navigationHandler = composeStrategies([
  // Get the precached header markup.
  () => matchPrecache('/partial-header.php'),
  // Get the content partial from the network.
  ({event}) => contentStrategy.handle(event),
  // Get the precached footer markup.
  () => matchPrecache('/partial-footer.php')
]);

// Register the streaming route for all navigation requests.
registerRoute(({request}) => request.mode === 'navigate', navigationHandler);

// Your service worker can end here, or you can add more
// logic to suit your needs, such as runtime caching, etc.

Mã này bao gồm 3 phần chính đáp ứng các yêu cầu sau:

  1. Chiến lược NetworkFirst được dùng để xử lý yêu cầu về một phần nội dung. Khi sử dụng chiến lược này, tên bộ nhớ đệm tuỳ chỉnh content sẽ được chỉ định để chứa các phần nội dung, cũng như một trình bổ trợ tuỳ chỉnh xử lý việc có nên đặt tiêu đề yêu cầu X-Content-Mode cho các trình duyệt không hỗ trợ tính năng tải trước điều hướng (và do đó không gửi tiêu đề Service-Worker-Navigation-Preload). Trình bổ trợ này cũng chỉ ra xem nên gửi một phần phiên bản lưu vào bộ nhớ đệm gần đây nhất của nội dung hay gửi một trang dự phòng ngoại tuyến trong trường hợp không có phiên bản được lưu vào bộ nhớ đệm nào cho yêu cầu hiện tại được lưu trữ.
  2. Phương thức strategy trong workbox-streams (đặt bí danh là composeStrategies ở đây) dùng để liên kết các phần của phần đầu trang và chân trang được lưu trước trong bộ nhớ đệm với nội dung được yêu cầu một phần từ mạng.
  3. Toàn bộ lược đồ được trang bị thông qua registerRoute cho các yêu cầu điều hướng.

Với logic này, chúng tôi đã thiết lập các câu trả lời theo thời gian thực. Tuy nhiên, có thể bạn sẽ phải làm một số việc trên hệ thống phụ trợ để đảm bảo rằng nội dung từ mạng là một phần của trang mà bạn có thể hợp nhất với các phần được lưu trước trong bộ nhớ đệm.

Nếu trang web của bạn có chương trình phụ trợ

Bạn nhớ lại rằng khi tính năng tải trước điều hướng đang bật, trình duyệt sẽ gửi một tiêu đề Service-Worker-Navigation-Preload có giá trị là true. Tuy nhiên, trong mã mẫu ở trên, chúng tôi đã gửi một tiêu đề tuỳ chỉnh X-Content-Mode trong hoạt động tải trước điều hướng sự kiện không được hỗ trợ trong trình duyệt. Trong phụ trợ, bạn sẽ thay đổi câu trả lời dựa trên sự hiện diện của những tiêu đề này. Trong phụ trợ PHP, URL này có thể trông giống như sau cho một trang nhất định:

<?php
// Check if we need to render a content partial
$navPreloadSupported = isset($_SERVER['HTTP_SERVICE_WORKER_NAVIGATION_PRELOAD']) && $_SERVER['HTTP_SERVICE_WORKER_NAVIGATION_PRELOAD'] === 'true';
$partialContentMode = isset($_SERVER['HTTP_X_CONTENT_MODE']) && $_SERVER['HTTP_X_CONTENT_MODE'] === 'partial';
$isPartial = $navPreloadSupported || $partialContentMode;

// Figure out whether to render the header
if ($isPartial === false) {
  // Get the header include
  require_once($_SERVER['DOCUMENT_ROOT'] . '/includes/site-header.php');

  // Render the header
  siteHeader();
}

// Get the content include
require_once('./content.php');

// Render the content
content($isPartial);

// Figure out whether to render the footer
if ($isPartial === false) {
  // Get the footer include
  require_once($_SERVER['DOCUMENT_ROOT'] . '/includes/site-footer.php');

  // Render the footer
  siteFooter();
}
?>

Trong ví dụ trên, các phần của nội dung được gọi dưới dạng các hàm. Các hàm này nhận giá trị của $isPartial để thay đổi cách kết xuất các phần đó. Ví dụ: hàm kết xuất content có thể chỉ bao gồm một số mã đánh dấu nhất định trong các điều kiện khi được truy xuất dưới dạng một phần. Chức năng này sẽ sớm được đề cập.

Những yếu tố nên cân nhắc

Trước khi triển khai trình chạy dịch vụ để phát trực tuyến và ghép các phần với nhau, bạn phải cân nhắc một số điều sau đây. Mặc dù đúng là việc sử dụng service worker theo cách này về cơ bản không thay đổi hành vi điều hướng mặc định của trình duyệt, nhưng có một số điều có thể bạn cần phải giải quyết.

Cập nhật các thành phần trang khi di chuyển

Phần phức tạp nhất trong phương pháp này là một số nội dung cần được cập nhật trên máy khách. Ví dụ: mã đánh dấu tiêu đề đang lưu trước vào bộ nhớ đệm có nghĩa là trang sẽ có cùng nội dung trong phần tử <title>, hoặc thậm chí bạn sẽ phải cập nhật trạng thái bật/tắt của các mục điều hướng trong mỗi lần điều hướng. Những nội dung này và các nội dung khác có thể được cập nhật trên ứng dụng cho mỗi yêu cầu điều hướng.

Để khắc phục vấn đề này, bạn có thể đặt một phần tử <script> cùng dòng vào một phần nội dung xuất phát từ mạng để cập nhật một số nội dung quan trọng:

<!-- The JSON below contains information about the current page. -->
<script id="page-data" type="application/json">'{"title":"Sand Wasp &mdash; World of Wasps","description":"Read all about the sand wasp in this tidy little post."}'</script>
<script>
  const pageData = JSON.parse(document.getElementById('page-data').textContent);

  // Update the page title
  document.title = pageData.title;
</script>
<article>
  <!-- Page content omitted... -->
</article>

Đây chỉ là một ví dụ về những việc bạn có thể phải làm nếu quyết định thiết lập trình chạy dịch vụ này. Ví dụ: đối với các ứng dụng phức tạp hơn có chứa thông tin người dùng, bạn có thể phải lưu trữ các bit dữ liệu có liên quan trong một cửa hàng trực tuyến như localStorage và cập nhật trang qua đó.

Xử lý mạng chậm

Một hạn chế của việc phát trực tuyến phản hồi sử dụng mã đánh dấu từ bộ nhớ đệm trước có thể xảy ra khi kết nối mạng chậm. Vấn đề là thẻ đánh dấu tiêu đề từ bộ nhớ đệm trước sẽ xuất hiện ngay lập tức, nhưng một phần nội dung từ mạng có thể mất khá nhiều thời gian mới xuất hiện sau lần hiển thị đầu tiên của mã đánh dấu tiêu đề.

Điều này có thể tạo ra trải nghiệm khó hiểu và nếu mạng quá chậm, bạn thậm chí có thể cảm thấy như trang bị hỏng và không hiển thị thêm nữa. Trong những trường hợp như vậy, bạn có thể chọn đặt biểu tượng đang tải hoặc thông báo trong phần đánh dấu của nội dung mà bạn có thể ẩn sau khi nội dung được tải.

Bạn có thể thực hiện việc này thông qua CSS. Giả sử tiêu đề của bạn kết thúc một phần bằng phần tử <article> đang mở và phần tử này sẽ được để trống cho đến khi có một phần nội dung để điền vào. Bạn có thể viết quy tắc CSS tương tự như sau:

article:empty::before {
  text-align: center;
  content: 'Loading...';
}

Phương thức này hoạt động nhưng sẽ hiển thị thông báo đang tải trên máy khách bất kể tốc độ mạng. Nếu muốn tránh thông báo ngẫu nhiên, bạn có thể thử phương pháp sau, trong đó chúng ta lồng bộ chọn trong đoạn mã ở trên trong một lớp slow:

.slow article:empty::before {
  text-align: center;
  content: 'Loading...';
}

Từ đây, bạn có thể sử dụng JavaScript trong tiêu đề một phần để đọc loại kết nối hiệu quả (ít nhất là trong trình duyệt Chromium) để thêm lớp slow vào phần tử <html> trên một số loại kết nối chọn lọc:

<script>
  const effectiveType = navigator?.connection?.effectiveType;

  if (effectiveType !== '4g') {
    document.documentElement.classList.add('slow');
  }
</script>

Điều này đảm bảo rằng các loại kết nối hiệu quả chậm hơn loại 4g sẽ nhận được thông báo đang tải. Sau đó, trong phần nội dung, bạn có thể đặt một phần tử <script> cùng dòng để xoá lớp slow khỏi HTML nhằm loại bỏ thông báo đang tải:

<script>
  document.documentElement.classList.remove('slow');
</script>

Cung cấp phản hồi dự phòng

Giả sử bạn đang sử dụng chiến lược ưu tiên mạng cho phần nội dung của mình. Nếu người dùng không có kết nối mạng và truy cập vào một trang họ đã từng truy cập, thì họ sẽ được bảo vệ. Tuy nhiên, nếu họ truy cập vào một trang mà họ chưa truy cập, họ sẽ không nhận được gì. Để tránh trường hợp này, bạn cần phân phát phản hồi dự phòng.

Mã cần thiết để đạt được phản hồi dự phòng được minh hoạ trong các mã mẫu trước đó. Quy trình này yêu cầu hai bước:

  1. Lưu trước vào bộ nhớ đệm một phản hồi dự phòng ngoại tuyến.
  2. Thiết lập lệnh gọi lại handlerDidError trong trình bổ trợ cho chiến lược ưu tiên mạng để kiểm tra bộ nhớ đệm của phiên bản truy cập gần đây nhất của trang. Nếu trang chưa từng được truy cập, bạn sẽ cần sử dụng phương thức matchPrecache từ mô-đun workbox-precaching để truy xuất phản hồi dự phòng từ bộ nhớ đệm trước.

Lưu vào bộ nhớ đệm và CDN

Nếu bạn đang dùng mẫu truyền trực tuyến này trong trình chạy dịch vụ, hãy đánh giá xem những trường hợp sau có áp dụng cho trường hợp của bạn không:

  • Bạn sử dụng CDN hoặc bất kỳ loại bộ nhớ đệm trung gian/công khai nào khác.
  • Bạn đã chỉ định tiêu đề Cache-Control với(các) lệnh max-age và/hoặc s-maxage khác 0 kết hợp với lệnh public.

Nếu bạn gặp cả hai trường hợp này, thì bộ nhớ đệm trung gian có thể giữ lại các phản hồi cho các yêu cầu điều hướng. Tuy nhiên, hãy nhớ rằng khi sử dụng mẫu này, bạn có thể phân phát hai phản hồi khác nhau cho bất kỳ URL nào:

  • Câu trả lời đầy đủ, chứa mục đánh dấu tiêu đề, nội dung và chân trang.
  • Phản hồi một phần, chỉ chứa nội dung.

Điều này có thể gây ra một số hành vi không mong muốn, dẫn đến việc đánh dấu tiêu đề và chân trang tăng gấp đôi, vì trình chạy dịch vụ có thể đang tìm nạp phản hồi đầy đủ từ bộ nhớ đệm CDN và kết hợp phản hồi đó với mã đánh dấu tiêu đề và chân trang được lưu trước trong bộ nhớ đệm.

Để giải quyết vấn đề này, bạn cần dựa vào tiêu đề Vary. Tiêu đề này ảnh hưởng đến hành vi lưu vào bộ nhớ đệm bằng cách khoá các phản hồi có thể lưu vào bộ nhớ đệm cho một hoặc nhiều tiêu đề có trong yêu cầu. Do chúng ta đang thay đổi phản hồi cho các yêu cầu điều hướng dựa trên tiêu đề của yêu cầu Service-Worker-Navigation-PreloadX-Content-Mode tuỳ chỉnh, nên chúng ta cần chỉ định tiêu đề Vary này trong phản hồi:

Vary: Service-Worker-Navigation-Preload,X-Content-Mode

Với tiêu đề này, trình duyệt sẽ phân biệt giữa phản hồi hoàn chỉnh và một phần cho các yêu cầu điều hướng, tránh các vấn đề với mã đánh dấu tiêu đề và chân trang tăng gấp đôi, cũng như mọi bộ nhớ đệm trung gian.

Kết quả

Hầu hết lời khuyên về hiệu suất trong thời gian tải đều tập trung vào "cho họ thấy những gì bạn có". Đừng ngần ngại, đừng đợi đến khi bạn có mọi thứ rồi mới hiển thị cho người dùng bất kỳ điều gì.

Jake Archibald trong bài viết Fun Hacks for Lỗi nhanh hơn

Các trình duyệt vượt trội khi xử lý phản hồi cho các yêu cầu điều hướng, ngay cả với các nội dung phản hồi HTML khổng lồ. Theo mặc định, các trình duyệt sẽ dần truyền trực tuyến và xử lý mã đánh dấu theo từng phần tránh các tác vụ dài, nhờ đó cải thiện hiệu suất khởi động.

Điều này mang lại lợi thế cho chúng ta khi sử dụng mẫu trình chạy dịch vụ truyền trực tuyến. Bất cứ khi nào bạn phản hồi một yêu cầu từ bộ nhớ đệm của trình chạy dịch vụ ngay từ đầu, thời điểm bắt đầu phản hồi sẽ đến gần như ngay lập tức. Khi kết hợp mã đánh dấu tiêu đề và chân trang được lưu trước trong bộ nhớ đệm với phản hồi của mạng, bạn sẽ có được một số lợi thế đáng chú ý về hiệu suất:

  • Thời gian cho byte đầu tiên (TTFB) thường sẽ giảm đáng kể, vì byte đầu tiên của phản hồi cho yêu cầu điều hướng là ngay lập tức.
  • Thời gian hiển thị nội dung đầu tiên (FCP) sẽ rất nhanh, vì mã đánh dấu tiêu đề được lưu trước trong bộ nhớ đệm sẽ chứa tham chiếu đến một biểu định kiểu được lưu vào bộ nhớ đệm, có nghĩa là trang sẽ hiển thị rất nhanh.
  • Trong một số trường hợp, Thời gian hiển thị nội dung lớn nhất (LCP) cũng có thể nhanh hơn, đặc biệt là nếu phần tử lớn nhất trên màn hình do tiêu đề được lưu trước trong bộ nhớ đệm cung cấp một phần. Mặc dù vậy, việc chỉ phân phát nội dung nào đó từ bộ nhớ đệm của trình chạy dịch vụ càng sớm càng tốt kết hợp với các tải trọng đánh dấu nhỏ hơn thì LCP tốt hơn.

Việc thiết lập và lặp lại các cấu trúc truyền trực tuyến có nhiều trang có thể hơi phức tạp, nhưng về mặt lý thuyết thì mức độ phức tạp của quá trình này thường không phức tạp hơn so với SPA. Lợi ích chính là bạn sẽ không thay thế giao thức điều hướng mặc định của trình duyệt mà sẽ cải thiện giao thức này.

Hơn thế nữa, Workbox giúp cho kiến trúc này không chỉ khả thi mà còn dễ dàng hơn so với trường hợp bạn tự triển khai kiến trúc này. Hãy dùng thử tính năng này trên trang web của chính bạn và xem trang web nhiều trang của bạn có thể nhanh hơn bao nhiêu cho người dùng trong lĩnh vực này.

Tài nguyên