前端進階

-

前端網頁實現自動儲存的 7 種方式

this.web

image

自動儲存是前端一個很細節功能,但對使用者的體驗影響很大。特別是在處理複雜表單系統或文檔編輯頁面時,自動儲存能大幅降低資料遺失的風險,也讓操作更加順暢。

在這篇文章中,我將帶你深入了解 7 種自動儲存的實作方式與關鍵細節,幫助你打造更穩定、良好的產品使用體驗。

一、固定時間間隔

在前端自動儲存中,固定時間間隔儲存(Interval Saving) 是最簡單直接的方式。它透過設定週期性時間(如每隔 5 秒)自動觸發儲存行為,特別適合用於短時間內頻繁輸入的表單或簡易筆記應用。

const interval = setInterval(() => {
  saveData(data)
}, 5000)

優點:

  • 實作簡單、穩定。
  • 適合短時間內頻繁輸入的場景。

缺點:

  • 無論資料是否有改變都會呼叫 API,容易造成不必要的請求。
  • 若儲存動作較複雜,會造成效能負擔。

最佳實踐:

  • 可以搭配判斷資料是否變動(hasChanges)來減少冗餘儲存。

二、動作間隔

若希望更貼近使用者輸入節奏,可以採用動作間隔(Debounce Saving) 的方式。這種方法會在使用者停止輸入一段時間後自動儲存,非常常見於編輯器或即時輸入表單中。

const handleChange = (e) => {
  debounce((data) => saveData(data), 1000)
}

優點:

  • 僅在輸入動作結束後才儲存,避免頻繁請求。
  • 更貼近使用者實際編輯行為。

缺點:

  • 若頁面在等待時間內被關閉,可能遺失最新資料。

最佳實踐:

  • 根據表單複雜度調整 debounce 時間。

三、偵測動作靜止

在需要更精準判斷使用者狀態的情況下,偵測使用者閒置(Idle Detection Saving) 是一種進階實作。它會監聽滑鼠與鍵盤活動,當使用者停止操作一段時間後自動觸發儲存。

let idleTimer

const resetIdleTimer = () => {
  clearTimeout(idleTimer)
  
  idleTimer = setTimeout(() => {
    saveData(data)
  }, 3000)
}

window.addEventListener('mousemove', resetIdleTimer)
window.addEventListener('keydown', resetIdleTimer)

優點:

  • 可降低 API 請求次數。
  • 更好地判斷使用者行為。

缺點:

  • 稍微複雜,需管理多個事件監聽。
  • 若 idle 判斷太短會頻繁觸發,太長又會失去即時性。

最佳實踐:

  • 建議 idle 閥值設定在 2~5 秒之間。
  • 也可搭配 localStorage 或 indexedDB 暫存,確保即使儲存失敗也不遺失資料。

四、焦點轉移時

另一種常見的前端自動儲存策略是焦點轉移觸發(Blur/Visibility Saving)。當使用者切換輸入框或離開當前頁籤時自動儲存,特別適合多欄位表單或長篇內容編輯器。

輸入框可以使用 onBlur 觸發,如果要偵測用戶是否最小化視窗或切換瀏覽器的 tab,則可以使用 visibilitychange 事件

const handleVisibilityChange = () => {
  if (document.visibilityState === 'hidden') {
    saveData(data)
  }
}

document.addEventListener('visibilitychange', handleVisibilityChange)

優點:

  • 更精穩的捕捉使用者離開前的狀態。
  • 適合表單類頁面或多欄位輸入。

缺點:

  • 若頁面因閃退或網路問題離開,仍可能遺失。
  • 若輸入框過多,或用戶快速切換輸入框,會頻繁觸發儲存事件。
  • 若輸入內容很大量,例如像 Notion 這種副文本的編輯,則不容易觸發自動儲存

最佳實踐:

  • 可以搭配 debounce 避免頻繁切換的情況

五、關閉頁面時

有時候使用者可能會不小心關閉頁面,我們可以使用 beforeunload 搭配 navigator.sendBeacon(),在關閉頁面後還能送資料給伺服器。

不使用傳統 fetch 是因為有些瀏覽器或環境在頁面關閉後就不能使用 http request 了,而 sendBeacon 可以避免這個問題。

const handleBeforeUnload = () => {
  navigator.sendBeacon('/api/save', data)
}

window.addEventListener('beforeunload', handleBeforeUnload)

優點:

  • sendBeacon 在頁面卸載階段仍可執行,不受瀏覽器阻擋。
  • 請求為非同步,不會影響頁面的關閉速度。

缺點:

  • 不支援舊版 IE、部分早期瀏覽器。
  • 某些瀏覽器對 sendBeacon 有大小限制,要注意。

最佳實踐:

  • 可搭配 localStorage 或 indexedDB 備份機制作雙保險。

六、網路斷開時

為了應對突發的網路中斷,離線暫存與自動同步機制是進階前端應用不可或缺的一環。這類自動儲存方式可在使用者離線時先暫存資料,待連線恢復後再自動同步到伺服器。

雖然沒網路時,我們不能傳送資料到伺服器做自動儲存,但可以先利用本地儲存,等用戶有網路後再做自動儲存。

const handleOffline = () => {
  localStorage.setItem('draft', JSON.stringify(data))
}

const handleOnline = () => {
  const draft = localStorage.getItem('draft')
  
  if (draft) {
    saveData(JSON.parse(draft))
    localStorage.removeItem('draft')
  }
}

window.addEventListener('offline', handleOffline)
window.addEventListener('online', handleOnline)

優點:

  • 保證即使網路中斷也不會遺失資料。

缺點:

  • 實作起來稍微複雜,也要考慮資料同步問題。
  • 若使用者清除暫存資料,仍會遺失資料。

最佳實踐:

  • 也搭配 IndexedDB 或 Service Worker 進行離線暫存以及恢復連線後的同步。
  • 斷線後顯示【網路已斷開】等提示

七、Websockets 斷聯時

這個方式比較適用於即時協作類應用(如 Google Docs),當偵測到 WebSocket 連線中斷時,自動觸發一次緊急儲存。

socket.onclose = () => {
  savedata(data)
}

優點:

  • 能確保協作資料在中斷前被保留。
  • 對即時編輯、多人文件特別關鍵。

缺點:

  • 依賴 WebSocket 狀態,不適用於非即時應用。
  • 若儲存邏輯與後端同步機制沒設計好,可能發生資料上的衝突。

最佳實踐:

  • 搭配版本號或編輯時間戳。
  • 斷線後可顯示暫存提示,等重連後自動同步。

總結

自動儲存雖然是很細節功能,但對使用者體驗與資料安全也非常重要。

無論是固定時間間隔、自動偵測輸入、還是離線儲存,每種方式都有其適用場景與取捨。
實務上,我們前端工程師通常會根據應用的性質與使用者行為,混合多種自動儲存策略來達到最佳的效果。

這篇文章主要是想提供自動儲存的思路,因此省略了一些像是資料同步、資料序列化、資料大小等細節,在自己專案上實作時仍要注意~!

資料參考:To save or to autosave: Autosaving patterns in modern web applications | by Brooklyn Dippo | Medium

你可能會感興趣的文章 👇