STEP GUIDE · Solution

這個步驟要做什麼、改哪裡、怎麼看結果

這一步聚焦 TASK-03;下方只比較「Checkpoint 2 → Solution」的真實異動。

01

三項 Task 進度

TASK-01已完成

訂閱主畫面並留下 adapter trace

預計修改:script.js

完成後:主畫面 subscriber 收到初始 snapshot,trace 顯示 subscribe 與 notify

TASK-02已完成

安全渲染並管理第二 Console subscriber

預計修改:script.js

完成後:留言以純文字渲染,Console subscriber 可訂閱並可 unsubscribe

TASK-03本步驟處理

模擬訂閱失敗、復原重試並新增留言

預計修改:script.js

完成後:失敗時保留舊留言且無幽靈 listener,retry 後畫面與 Console subscriber 同時收到新 snapshot

02

HTML、CSS、JavaScript 與文件實際異動

展開檔案卡查看必要差異;只有程式碼區可以橫向捲動。

HTML本步驟無異動

檔案:index.html

修改前

前一步與本步驟沒有實質差異。

修改後

本步驟不需修改此語言。
CSS本步驟無異動

檔案:style.css

修改前

前一步與本步驟沒有實質差異。

修改後

本步驟不需修改此語言。
JavaScript本步驟有異動

檔案:script.js

修改前

  if (unsubscribeView) unsubscribeView();
  unsubscribeView = adapter.subscribe((snapshot) => {
    status.textContent = `主畫面收到 ${snapshot.length} 筆 snapshot`;
    renderMessages(snapshot);
  }, "主畫面");

修改後

const form = document.querySelector("#message-form");
const input = document.querySelector("#message-input");
const submitButton = document.querySelector("#message-submit");
const failureButton = document.querySelector("#simulate-subscribe-failure");
const retryButton = document.querySelector("#retry-subscription");
  if (unsubscribeView) {
    unsubscribeView();
    unsubscribeView = null;
  }
  status.textContent = "訂閱中…";
  try {
    unsubscribeView = adapter.subscribe((snapshot) => {
      status.textContent = `主畫面收到 ${snapshot.length} 筆 snapshot`;
      renderMessages(snapshot);
    }, "主畫面");
    retryButton.disabled = true;
  } catch (error) {
    status.textContent = `訂閱失敗:${error.message};舊留言已保留,請重試。`;
    retryButton.disabled = false;
  }
function addMessage(text) {
  const cleanText = text.trim();
  if (!cleanText) {
    status.textContent = "請先輸入留言";
    return;
  }
  if (!unsubscribeView) {
    status.textContent = "主畫面尚未訂閱,請先按重試訂閱。";
    return;
  }
  adapter.push(cleanText);
  input.value = "";
}
failureButton.disabled = false;
submitButton.disabled = false;
failureButton.addEventListener("click", () => {
  adapter.failNextSubscribe();
  startListening();
});
retryButton.addEventListener("click", startListening);
form.addEventListener("submit", (event) => {
  event.preventDefault();
  addMessage(input.value);
});
README/其他文件本練習未使用

檔案:README.md

修改前

本練習沒有這個檔案。

修改後

本步驟不需修改此語言。
03

怎麼看到結果

  1. 準備

    先在 Solution 開啟 Console subscriber,並記住目前留言與 trace 的訂閱者數量。

  2. 操作

    按「模擬下次訂閱失敗」,確認舊留言未被清空;再按「重試訂閱」,新增一筆留言並對照畫面、Console 與 trace。

  3. 預期

    失敗時保留舊留言且無幽靈 listener,retry 後畫面與 Console subscriber 同時收到新 snapshot

Solution TASK-03

模擬訂閱失敗、復原重試並新增留言

完成後可見:失敗時保留舊留言且無幽靈 listener,retry 後畫面與 Console subscriber 同時收到新 snapshot

MEMORY ADAPTER(只練介面,不是 Firebase 連線)

可追蹤的即時留言

本頁每次重新整理都會建立獨立記憶體,不會跨分頁同步。

尚未訂閱

訂閱生命週期控制

目前 subscriber:0 個

Adapter trace