Thứ hai, 13/01/2020 | 00:00 GMT+7

Cách sử dụng API BroadcastChannel trong JavaScript


API BroadcastChannel là một API nền tảng web mới cho phép bạn giao tiếp giữa các cửa sổ / tab / iframe khác nhau có cùng nguồn root . Sử dụng BroadcastChannel nghe có vẻ lạ mắt và khó khăn nhưng nó rất dễ dàng và hữu ích.

Tại sao sử dụng API BroadcastChannel

Cố gắng đăng nhập vào một trong những trang web yêu thích của bạn (tôi đã thử trên youtube.com). Sau đó, mở trong một tab riêng của cùng một trang web. Thông thường bạn sẽ đăng nhập vào cả hai trang. Sau đó đăng xuất trên một trong các tab của bạn. Trên hầu hết các trang web, có vẻ như bạn đang đăng nhập vào một trang và đăng xuất khỏi trang kia.

Các cửa sổ của bạn ở các trạng thái khác nhau: đã đăng nhập và đã đăng xuất. Điều đó không tuyệt vời và nếu bạn là một người nghiện tabber (như tôi), nó có thể dẫn đến một số nhầm lẫn.

Đây thậm chí có thể là một vấn đề bảo mật. Hãy tưởng tượng user của bạn đang ở một quán cà phê bằng cách sử dụng console của công ty. Anh ấy đăng xuất để đi vệ sinh và để máy tính. Nếu ứng dụng được mở trong nhiều tab, người ta có thể truy cập dữ liệu có sẵn trong các tab khác (trên màn hình hoặc có thể là một số mã thông báo JWT).

Mã API BroadcastChannel

Đây là một ví dụ rất đơn giản mà bạn có thể sao chép paste vào file HTML local :

<!DOCTYPE html>

<body>
  <!-- The title will change to greet the user -->
  <h1 id="title">Hey</h1>
  <input id="name-field" placeholder="Enter Your Name"/>
</body>

<script>

var bc = new BroadcastChannel('gator_channel');

(()=>{
  const title = document.getElementById('title');
  const nameField = document.getElementById('name-field');
  const setTitle = (userName) => {
    title.innerHTML = 'Hey ' + userName;
  }

  bc.onmessage = (messageEvent) => {
    // If our broadcast message is 'update_title' then get the new title from localStorage
    if (messageEvent.data === 'update_title') {
      // localStorage is domain specific so when it changes in one window it changes in the other
      setTitle(localStorage.getItem('title'));
    }
  }

  // When the page loads check if the title is in our localStorage
  if (localStorage.getItem('title')) {
    setTitle(localStorage.getItem('title'));
  } else {
    setTitle('please tell us your name');
  }

  nameField.onchange = (e) => {
    const inputValue = e.target.value;
    // In the localStorage we set title to the user's input
    localStorage.setItem('title', inputValue);
    // Update the title on the current page 
    setTitle(inputValue);
    // Tell the other pages to update the title
    bc.postMessage('update_title');
  }
})()
</script>

Trang này có tiêu đề và đầu vào. Khi user nhập vào tên của cô ấy trong đầu vào ta lưu trữ tên trong lưu trữ local dưới sự chủ chốt userName . Sau đó, ta đặt tiêu đề ứng dụng của bạn thành 'Hey' + userName . Vì vậy, nếu tên của user là Sarah , trang sẽ hiển thị "Hey Sarah".

Nếu ta không có BroadcastChannel khi user nhập tên của cô ấy vào một cửa sổ, nó sẽ không cập nhật cửa sổ kia. Nếu không có kênh quảng bá trong mã của ta , user sẽ phải làm mới cửa sổ thứ hai để cập nhật tiêu đề.

Vì vậy, trong dòng đầu tiên, ta tạo một BroadcastChannel tên là “gator_channel”. Sau đó, ta tạo một bộ nhận tin nhắn bằng phương pháp onmessage . Ta đặt onmessage thành một hàm nhận một đối số (hay còn gọi là thông báo sự kiện). Sau đó, trong mã của ta , ta kiểm tra xem tên của thư là update_title . Nếu vậy, ta extract tên user từ bộ nhớ local .

Khi nào ta gọi postMessage trên kênh quảng bá, nó sẽ gọi onmessage trong các cửa sổ khác. Vì vậy, nếu tôi nhập Jack trong cửa sổ 1, thì cửa sổ 1 sẽ gọi bc.postMessage('updated_title') . Thao tác này sẽ kích hoạt onmessage trên cửa sổ 2 và bất kỳ cửa sổ nào khác được mở trên cùng nguồn root .

Nơi nó sẽ hoạt động

Không giống như các API khác như window.postMessage , bạn không cần biết bất cứ điều gì về các cửa sổ hoặc tab khác đã mở. Kênh phát sẽ hoạt động trên bất kỳ tab hoặc cửa sổ nào có cùng nguồn root (cùng một schemas , server và cổng).

Điều này nghĩa là bạn có thể phát tin nhắn từ https://alligator.io/ đến https://alligator.io/js/broadcast-channels . Tất cả những gì bạn cần là có một đối tượng BroadcastChanel trên cả hai trang sử dụng cùng một tên kênh:

const bc = new BroadcastChannel('alligator_channel');
bc.onmessage = (eventMessage) => {
  // do something different on each page
}

Nếu các server khác nhau, nó sẽ không hoạt động:

Nếu các cổng khác nhau, nó sẽ không hoạt động:

Nếu các chương trình khác nhau, nó sẽ không hoạt động. Điều đó tương tự với các cổng khác nhau vì tiêu chuẩn là http và https tương ứng sử dụng cổng 80 và 443:

Các kênh quảng bá sẽ không hoạt động nếu một trong các cửa sổ ở chế độ ẩn danh hoặc trên các trình duyệt (ví dụ: Firefox đến Chrome).

Tính tương thích của trình duyệt web

Theo (caniuse.com) [ https://caniuse.com/#feat=broadcastchannel] , API BroadcastChannel có sẵn cho khoảng 75,6% user . Safari và Internet Explorer chưa có bất kỳ hỗ trợ nào cho nó.

Theo hiểu biết của tôi, polyfill phổ biến nhất là cái này . Bạn có thể sử dụng nó gần giống như API BroadcastChannel. Nếu phát hiện có sẵn API BroadcastChannel, nó sẽ tự động sử dụng nó để có kết quả nhanh hơn. Nếu không, nó sẽ sử dụng IndexedDB hoặc LocalStorage.

Ta có thể vượt qua những thông điệp nào?

Bạn có thể chuyển bất kỳ thứ gì có thể được nhân bản bằng cách sử dụng thuật toán nhân bản có cấu trúc. Điều đó bao gồm hầu hết mọi thứ ngoại trừ các ký hiệu:

  • Tất cả các kiểu nguyên thủy ngoại trừ các ký hiệu (Boolean, Null, Undefined, Number, BigInt, String)
  • Đối tượng Boolean và String
  • ngày
  • Biểu thức chính quy
  • Blobs
  • Tệp, Danh sách file
  • ArrayBuffers, ArrayBufferViews
  • ImageBitmaps, ImageDatas
  • Mảng, Đối tượng, Bản đồ và Bộ

Nếu bạn thử gửi một cái gì đó giống như Biểu tượng, bạn sẽ gặp lỗi ở phía gửi.


Hãy cập nhật mã của ta và sử dụng các đối tượng thay vì chuỗi.

  bc.onmessage = (messageEvent) => {
    const data = messageEvent.data
    // If our broadcast message is 'update_title' then get the new title from localStorage
    switch (data.type) {
      case 'update_title':
        if (data.title){
          setTitle(data.title);
        }
        else
          setTitle(localStorage.getItem('title'));
        break
      default:
        console.log('we received a message')
    }
  };
  // ... Skipping Code
  bc.postMessage({type: 'update_title', title: inputValue});

Những điều bạn có thể làm với các kênh phát sóng

Có rất nhiều điều ta có thể tưởng tượng. Trường hợp sử dụng rõ ràng nhất là chia sẻ trạng thái. Ví dụ: nếu bạn sử dụng thông tin như Flux hoặc Redux để quản lý trạng thái của bạn , bạn có thể phát một thông báo để cửa hàng của bạn giữ nguyên trên các tab. Ta cũng có thể tưởng tượng việc xây dựng một cái gì đó tương tự cho các máy trạng thái.

Ta thấy rằng ta cũng có thể gửi các file lớn ở các định dạng khác nhau. Ta có thể tiết kiệm băng thông bằng cách chia sẻ các file lớn như hình ảnh trên các tab.

Đóng kênh phát sóng

Việc đóng một kênh quảng bá rất dễ dàng. Bạn chỉ cần chạy phương thức close trên kênh quảng bá của bạn :

bc.close()

Bạn có thể cần đóng hoặc mở các kênh tùy thuộc vào trạng thái ứng dụng của bạn . Ví dụ: khi đăng nhập, bạn có thể có một kênh cụ thể để chia sẻ trạng thái ứng dụng của bạn . Bạn có thể cần đóng kênh đó khi đăng xuất.


Tags:

Các tin liên quan

Đa năng hóa chuỗi trong JavaScript bằng Simplur
2020-01-10
Hướng dẫn nhanh về phương pháp đối sánh chuỗi trong JavaScript
2020-01-07
Tham quan API quyền JavaScript
2020-01-05
V8 của V8: Chuỗi liên kết tùy chọn và kết hợp Nullish trong JavaScript
2019-12-29
Phân tích cú pháp, xác thực, thao tác và hiển thị ngày và giờ trong JavaScript với Day.js
2019-12-28
Cách bắt đầu với API hiệu suất JavaScript
2019-12-25
Xem xét tất cả 13 bẫy proxy JavaScript
2019-12-19
Khám phá phương thức indexOf cho chuỗi và mảng trong JavaScript
2019-12-17
Thao tác DOM trong JavaScript với innerText và innerHTML
2019-12-14
Cách gói một gói JavaScript Vanilla để sử dụng trong React
2019-12-12