Kiến trúc ứng dụng web lũy tiến: Các mẫu JavaScript Service Worker | MLOG | MLOG

4. Chỉ Mạng (Network-Only)

Chiến lược chỉ mạng luôn tìm nạp tài sản từ mạng, bỏ qua hoàn toàn bộ nhớ đệm. Chiến lược này được sử dụng khi bạn hoàn toàn cần phiên bản mới nhất của một tài nguyên và không muốn caching.

Ví dụ:

            
self.addEventListener('fetch', event => {
  event.respondWith(
    fetch(event.request)
  );
});

            

5. Cũ trong khi xác thực lại (Stale-While-Revalidate)

Chiến lược stale-while-revalidate phục vụ tài sản đã được cache ngay lập tức, đồng thời tìm nạp phiên bản mới nhất từ mạng. Khi yêu cầu mạng hoàn tất, cache sẽ được cập nhật với phiên bản mới. Chiến lược này cung cấp phản hồi ban đầu nhanh chóng trong khi đảm bảo rằng người dùng cuối cùng sẽ nhận được nội dung cập nhật nhất. Đây là một chiến lược hữu ích cho nội dung không quan trọng mà tốc độ được ưu tiên hơn sự mới mẻ tuyệt đối.

Ví dụ:

            
self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request)
      .then(response => {
        const fetchPromise = fetch(event.request).then(networkResponse => {
          caches.open('my-cache').then(cache => {
            cache.put(event.request, networkResponse.clone());
            return networkResponse;
          });
        });
        return response || fetchPromise;
      })
  );
});

            

6. Cache, sau đó là Mạng (Cache, then Network)

Tương tự như stale-while-revalidate nhưng không trả về ngay tài sản đã được cache. Nó kiểm tra cache trước, và chỉ khi tài sản có mặt thì yêu cầu mạng mới được tiến hành trong nền để cập nhật cache.

Chọn chiến lược Caching phù hợp

Chiến lược caching tối ưu phụ thuộc vào các yêu cầu cụ thể của ứng dụng của bạn. Hãy xem xét các yếu tố như:

Bằng cách lựa chọn cẩn thận các chiến lược caching phù hợp, bạn có thể cải thiện đáng kể hiệu suất và trải nghiệm người dùng của PWA, ngay cả trong môi trường ngoại tuyến. Các công cụ như Workbox ([https://developers.google.com/web/tools/workbox](https://developers.google.com/web/tools/workbox)) có thể đơn giản hóa việc triển khai các chiến lược này.

Đồng bộ hóa nền: Xử lý các thay đổi khi ngoại tuyến

Đồng bộ hóa nền cho phép PWA của bạn thực hiện các tác vụ trong nền, ngay cả khi người dùng ngoại tuyến. Điều này đặc biệt hữu ích để xử lý việc gửi biểu mẫu, cập nhật dữ liệu và các hoạt động khác yêu cầu kết nối mạng. API `BackgroundSyncManager` cho phép bạn đăng ký các tác vụ sẽ được thực thi khi có mạng.

Đăng ký một tác vụ đồng bộ nền

Để đăng ký một tác vụ đồng bộ nền, bạn cần sử dụng phương thức `register` của `BackgroundSyncManager`. Phương thức này nhận một tên thẻ (tag) duy nhất làm đối số. Tên thẻ xác định tác vụ cụ thể sẽ được thực hiện.

Ví dụ:

            
self.addEventListener('sync', event => {
  if (event.tag === 'my-sync-task') {
    event.waitUntil(doSomeWork());
  }
});

            

Xử lý sự kiện đồng bộ (Sync Event)

Khi trình duyệt phát hiện có kết nối mạng, nó sẽ gửi một sự kiện `sync` đến service worker. Bạn có thể lắng nghe sự kiện này và thực hiện các hành động cần thiết, chẳng hạn như gửi dữ liệu đến máy chủ.

Ví dụ:

            
async function doSomeWork() {
  // Retrieve data from IndexedDB
  const data = await getDataFromIndexedDB();

  // Send data to the server
  try {
    const response = await fetch('/api/sync', {
      method: 'POST',
      body: JSON.stringify(data),
      headers: {
        'Content-Type': 'application/json'
      }
    });

    if (response.ok) {
      // Clear the data from IndexedDB
      await clearDataFromIndexedDB();
    } else {
      // Handle errors
      console.error('Sync failed:', response.status);
      throw new Error('Sync failed');
    }
  } catch (error) {
    // Handle network errors
    console.error('Network error:', error);
    throw error;
  }
}

            

Ví dụ: Gửi biểu mẫu khi ngoại tuyến

Hãy tưởng tượng một kịch bản nơi người dùng điền vào một biểu mẫu khi ngoại tuyến. Service worker có thể lưu trữ dữ liệu biểu mẫu trong IndexedDB và đăng ký một tác vụ đồng bộ nền. Khi có mạng, service worker sẽ truy xuất dữ liệu biểu mẫu từ IndexedDB và gửi nó đến máy chủ.

  1. Người dùng điền vào biểu mẫu và nhấp vào gửi khi ngoại tuyến.
  2. Dữ liệu biểu mẫu được lưu trữ trong IndexedDB.
  3. Một tác vụ đồng bộ nền được đăng ký với một thẻ duy nhất (ví dụ: `form-submission`).
  4. Khi có mạng, sự kiện `sync` được kích hoạt.
  5. Service worker truy xuất dữ liệu biểu mẫu từ IndexedDB và gửi nó đến máy chủ.
  6. Nếu việc gửi thành công, dữ liệu biểu mẫu sẽ bị xóa khỏi IndexedDB.

Thông báo đẩy: Tương tác với người dùng bằng các cập nhật kịp thời

Thông báo đẩy cho phép PWA của bạn gửi các cập nhật và tin nhắn kịp thời đến người dùng, ngay cả khi ứng dụng không hoạt động tích cực trong trình duyệt. Điều này có thể cải thiện đáng kể sự tương tác và giữ chân người dùng. Push API và Notifications API hoạt động cùng nhau để gửi thông báo đẩy.

Đăng ký nhận thông báo đẩy

Để nhận thông báo đẩy, người dùng trước tiên phải cấp quyền cho PWA của bạn. Bạn có thể sử dụng API `PushManager` để đăng ký người dùng nhận thông báo đẩy.

Ví dụ:

            
navigator.serviceWorker.ready.then(registration => {
  registration.pushManager.subscribe({
    userVisibleOnly: true,
    applicationServerKey: 'YOUR_PUBLIC_VAPID_KEY'
  })
  .then(subscription => {
    // Send subscription details to your server
    sendSubscriptionToServer(subscription);
  })
  .catch(error => {
    console.error('Failed to subscribe:', error);
  });
});

            

Quan trọng: Thay thế `YOUR_PUBLIC_VAPID_KEY` bằng khóa VAPID (Voluntary Application Server Identification) công khai thực tế của bạn. Các khóa VAPID được sử dụng để xác định máy chủ ứng dụng của bạn và đảm bảo rằng thông báo đẩy được gửi một cách an toàn.

Xử lý thông báo đẩy

Khi nhận được thông báo đẩy, service worker sẽ gửi một sự kiện `push`. Bạn có thể lắng nghe sự kiện này và hiển thị thông báo cho người dùng.

Ví dụ:

            
self.addEventListener('push', event => {
  const payload = event.data ? event.data.text() : 'No payload';

  event.waitUntil(
    self.registration.showNotification('My PWA', {
      body: payload,
      icon: 'icon.png'
    })
  );
});

            

Tùy chỉnh thông báo đẩy

API Notifications cho phép bạn tùy chỉnh giao diện và hành vi của thông báo đẩy. Bạn có thể chỉ định tiêu đề, nội dung, biểu tượng, huy hiệu và các tùy chọn khác.

Ví dụ:

            
self.addEventListener('push', event => {
  const data = event.data.json();
  const title = data.title || 'My PWA';
  const options = {
    body: data.body || 'No message',
    icon: data.icon || 'icon.png',
    badge: data.badge || 'badge.png',
    vibrate: [200, 100, 200],
    data: { // Custom data that you can access when the user clicks the notification
      url: data.url || '/'
    },
    actions: [
      {action: 'explore', title: 'Explore this new world',
        icon: 'images/checkmark.png'},
      {action: 'close', title: 'Close',
        icon: 'images/xmark.png'},
    ]
  };

  event.waitUntil(self.registration.showNotification(title, options));
});


self.addEventListener('notificationclick', function(event) {
  event.notification.close();

  // Check if the user clicked on an action.
  if (event.action === 'explore') {
    clients.openWindow(event.notification.data.url);
  } else {
    // Default action: open the app.
    clients.openWindow('/');
  }
});

            

Ví dụ: Cảnh báo tin tức

Một ứng dụng tin tức có thể sử dụng thông báo đẩy để cảnh báo người dùng về các tin tức nóng. Khi một bài báo mới được xuất bản, máy chủ sẽ gửi thông báo đẩy đến thiết bị của người dùng, hiển thị một bản tóm tắt ngắn gọn của bài báo. Sau đó, người dùng có thể nhấp vào thông báo để mở toàn bộ bài báo trong PWA.

Các mẫu Service Worker nâng cao

1. Phân tích ngoại tuyến (Offline Analytics)

Theo dõi hành vi của người dùng ngay cả khi họ ngoại tuyến bằng cách lưu trữ dữ liệu phân tích cục bộ và gửi nó đến máy chủ khi có mạng. Điều này có thể đạt được bằng cách sử dụng IndexedDB và Background Sync.

2. Quản lý phiên bản và cập nhật

Triển khai một chiến lược quản lý phiên bản mạnh mẽ cho service worker của bạn để đảm bảo rằng người dùng luôn nhận được các bản cập nhật mới nhất mà không làm gián đoạn trải nghiệm của họ. Sử dụng các kỹ thuật cache busting để làm mất hiệu lực các tài sản đã được cache cũ.

3. Service Worker theo Module

Tổ chức mã service worker của bạn thành các module để cải thiện khả năng bảo trì và đọc hiểu. Sử dụng JavaScript modules (ESM) hoặc một trình đóng gói module như Webpack hoặc Rollup.

4. Caching động

Lưu trữ tài sản vào cache một cách linh hoạt dựa trên tương tác và mô hình sử dụng của người dùng. Điều này có thể giúp tối ưu hóa kích thước cache và cải thiện hiệu suất.

Các thực tiễn tốt nhất cho việc phát triển Service Worker

Kết luận

JavaScript service worker là những công cụ mạnh mẽ để xây dựng các PWA mạnh mẽ, hiệu suất cao và hấp dẫn. Bằng cách hiểu vòng đời của service worker và triển khai các chiến lược caching, đồng bộ hóa nền và thông báo đẩy phù hợp, bạn có thể tạo ra những trải nghiệm người dùng đặc biệt, ngay cả trong môi trường ngoại tuyến. Bài viết này đã khám phá các mẫu service worker chính và các thực tiễn tốt nhất để hướng dẫn bạn xây dựng các PWA thành công cho đối tượng người dùng toàn cầu. Khi web tiếp tục phát triển, service worker sẽ đóng một vai trò ngày càng quan trọng trong việc định hình tương lai của phát triển web.

Hãy nhớ điều chỉnh các mẫu này cho phù hợp với yêu cầu ứng dụng cụ thể của bạn và luôn ưu tiên trải nghiệm người dùng. Bằng cách tận dụng sức mạnh của service worker, bạn có thể tạo ra các PWA không chỉ hoạt động tốt mà còn thú vị khi sử dụng, bất kể vị trí hay kết nối mạng của người dùng.

Tài nguyên tham khảo thêm: