perf: 今日页首屏 394KB/2.0s → 51.5KB/0.82s
逐个接口计时后的两处改动: - 健康摘要不再下发空值。一天 40 项指标里大部分是这块表没有的传感器, 全按 null 发出去占了约两成体积。客户端本来就把「键不存在」和 null 当同一回事。 - 今日页首屏由 365 天改为 60 天,往前翻越界时再加载 180 天。 一次取一年是为了让翻页不发请求,代价是首屏 394 KB,手机上不划算。 日历选到窗口外的日期同样会自动加载。 顺带把加载逻辑收成一个 loadFrom:原来初始 effect 的依赖是空数组, 日历里改 from 不会触发重新拉取,是个还没被触发的 bug。 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -37,7 +37,13 @@ def get_summary(user_id, start=None, end=None):
|
||||
for r in rows:
|
||||
day = {"date": r["date"]}
|
||||
for column, key in HEALTH_COLUMNS.items():
|
||||
day[key] = r.get(column)
|
||||
value = r.get(column)
|
||||
# Null metrics are omitted rather than sent as null. A year of 40
|
||||
# metrics is 394 KB over the tunnel, and most of it is nulls for
|
||||
# sensors this watch does not have; the client already treats a
|
||||
# missing key and a null the same way.
|
||||
if value is not None:
|
||||
day[key] = value
|
||||
# Sleep stays nested for backwards compatibility with the UI and the
|
||||
# existing recommendation rules.
|
||||
day["sleep"] = (
|
||||
|
||||
@@ -119,12 +119,17 @@ class TestUpsert:
|
||||
b = health_svc.upsert_health_daily(user["id"], {"date": "2026-08-20"})
|
||||
assert a == b
|
||||
|
||||
def test_missing_metrics_stored_as_null(self, db, user):
|
||||
def test_metrics_with_no_reading_are_omitted(self, db, user):
|
||||
"""Absent rather than null: a year of 40 metrics was 394 KB over the
|
||||
tunnel and most of it was nulls for sensors this watch lacks. The UI
|
||||
reads a missing key and a null the same way."""
|
||||
health_svc.upsert_health_daily(
|
||||
user["id"], {"date": "2026-08-20", "steps": 100}
|
||||
)
|
||||
row = health_svc.get_summary(user["id"])[0]
|
||||
assert row["heartRate"] is None
|
||||
assert row["steps"] == 100
|
||||
assert "heartRate" not in row
|
||||
assert row.get("heartRate") is None, "reading it must still be falsy"
|
||||
assert row["sleep"] is None
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user