การสร้าง Real-time Web Application คงหลีกเลี่ยงไม่ได้กับการใช้ WebSocket เพื่อให้เกิดการสื่อสารแบบสองทาง (Bi-direction Communication) เพื่อให้ฝั่ง Backend สามารถอัพเดตข้อมูลให้กับ Frontend ได้ สำหรับ Rails ก็มี ActionCable เพื่อจัดการในส่วนของ WebSocket ให้กับเรา
ที่นี้โจทย์เรามีอยู่ว่าในกรณีที่เรามีการใช้ turbo_stream_from จาก Turbo ซึ่งจะมีการสร้าง WebSocket Connection ขึ้นมาอยู่แล้ว 1 ช่อง และถ้าเราอยากจะให้เพิ่มช่องทางให้ในการส่งข้อมูลอื่นๆ ยกตัวอย่างเช่น ข้อมูล chat, ข้อมูลสถานะ เราจะสร้าง Connection ใหม่ขึ้นมา
// chat_controller.js import { Controller } from "stimulus" import consumer from '../channels/consumer' export default class extends Controller { connect() { this.channel = consumer.subscriptions.create( { channel: 'ChatChannel', room: 'Funny' }, { connected: this.cableConnected.bind(this), disconnected: this.cableDisconnected.bind(this), received: this.cableReceived.bind(this) } ) ... }
# chat_channel.rb class ChatChannel < ApplicationCable::Channel def subscribed stream_from "chat_#{params[:room].split.join.underscore}" end end
เมื่อเรารันโปรแกรม และเปิดดูใน Inspector ในส่วนของ Network และกรองดูเฉพาะ WS ก็จะพบว่า WebSocket Connection ที่ถูกสร้างขึ้นมีตั้ง 2 ช่องด้วยกัน
- ช่องทางที่สร้างจาก Turbo
- ช่องทางที่สร้างจาก ActionCable
แน่นอนว่าเว็บแอพพลิเคชันของเราจะต้องเปิด Connection ถึง 2 ช่อง ทำให้ Server ก็ต้องแบกรับภาระมากขึ้น รวมถึงข้อจำกัดจำนวน Connection ที่ Server ตัวหนึ่งๆ จะรองรับ ทำให้ต้องเกิดการขยับขยายขึ้น เพื่อเป็นการเพิ่มประสิทธิภาพให้กับ Server อย่างน้อยเราก็ขอพยายาม Optimize Connection กันหน่อย โดยพยายามรวบ Connection ให้เหลือช่องทางเดียว เพียงเราเปลี่ยนจากการสร้าง Channel จาก ActionCable มาเป็นการสร้าง Channel จาก Turbo
import { Controller } from "stimulus" import { subscribeTo } from '@hotwired/turbo-rails/app/javascript/turbo/cable'
export default class extends Controller { async connect() { await delay(200) this.channel = subscribeTo( { channel: "ChatChannel", room: "Best Room" }, { connected: this.cableConnected.bind(this), disconnected: this.cableDisconnected.bind(this), received: this.cableReceived.bind(this) } ) ) }
จากโค้ดข้างต้นจะพบว่าเราจะเรียกใช้งาน subscribeTo ซึ่งเป็นฟังก์ชันที่ใช้สำหรับสร้าง Channel ของ Turbo โดยใช้ Connection เดิมที่ Turbo ได้สร้างสขึ้นมา เพียงเท่านี้เราก็ Optimize ให้ Server ของเราได้แล้ว