refactor(离线缓存): 优化网络监听器注销逻辑并添加注释
确保网络监听器注销时的状态闭环 添加详细的类型定义和代码注释
Showing
2 changed files
with
20 additions
and
2 deletions
| 1 | /* | 1 | /* |
| 2 | * @Date: 2025-06-28 10:33:00 | 2 | * @Date: 2025-06-28 10:33:00 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2026-01-17 00:22:34 | 4 | + * @LastEditTime: 2026-01-17 12:14:16 |
| 5 | * @FilePath: /xyxBooking-weapp/src/app.js | 5 | * @FilePath: /xyxBooking-weapp/src/app.js |
| 6 | * @Description: 应用入口文件 | 6 | * @Description: 应用入口文件 |
| 7 | */ | 7 | */ |
| ... | @@ -168,6 +168,7 @@ const App = createApp({ | ... | @@ -168,6 +168,7 @@ const App = createApp({ |
| 168 | * - 尝试在网络可用时预加载离线预约数据 | 168 | * - 尝试在网络可用时预加载离线预约数据 |
| 169 | * - 启动离线预约缓存轮询(会自行处理网络可用性与引用计数) | 169 | * - 启动离线预约缓存轮询(会自行处理网络可用性与引用计数) |
| 170 | */ | 170 | */ |
| 171 | + | ||
| 171 | const bootstrap_after_auth = () => { | 172 | const bootstrap_after_auth = () => { |
| 172 | try_preload_when_online() | 173 | try_preload_when_online() |
| 173 | enable_offline_booking_cache_polling({ interval_ms: 2 * 1000 * 60 }) | 174 | enable_offline_booking_cache_polling({ interval_ms: 2 * 1000 * 60 }) |
| ... | @@ -184,6 +185,8 @@ const App = createApp({ | ... | @@ -184,6 +185,8 @@ const App = createApp({ |
| 184 | * - 授权成功后调用 bootstrap_after_auth 启动共用逻辑 | 185 | * - 授权成功后调用 bootstrap_after_auth 启动共用逻辑 |
| 185 | * - 授权失败则跳转至授权页面 | 186 | * - 授权失败则跳转至授权页面 |
| 186 | */ | 187 | */ |
| 188 | + | ||
| 189 | + // 如果用户已授权,则直接调用 bootstrap_after_auth 启动共用逻辑 | ||
| 187 | if (hasAuth()) { | 190 | if (hasAuth()) { |
| 188 | bootstrap_after_auth() | 191 | bootstrap_after_auth() |
| 189 | return | 192 | return | ... | ... |
| ... | @@ -8,6 +8,7 @@ import { get_network_type, is_usable_network } from '@/utils/network' | ... | @@ -8,6 +8,7 @@ import { get_network_type, is_usable_network } from '@/utils/network' |
| 8 | 8 | ||
| 9 | /** | 9 | /** |
| 10 | * @description: 轮询状态 | 10 | * @description: 轮询状态 |
| 11 | + * @typedef {Object} PollingState | ||
| 11 | * @property {Number} timer_id 轮询定时器id | 12 | * @property {Number} timer_id 轮询定时器id |
| 12 | * @property {Boolean} running 是否正在轮询 | 13 | * @property {Boolean} running 是否正在轮询 |
| 13 | * @property {Boolean} in_flight 是否正在刷新 | 14 | * @property {Boolean} in_flight 是否正在刷新 |
| ... | @@ -20,6 +21,7 @@ import { get_network_type, is_usable_network } from '@/utils/network' | ... | @@ -20,6 +21,7 @@ import { get_network_type, is_usable_network } from '@/utils/network' |
| 20 | * @property {Promise} network_listener_promise 网络监听器Promise | 21 | * @property {Promise} network_listener_promise 网络监听器Promise |
| 21 | */ | 22 | */ |
| 22 | 23 | ||
| 24 | +/** @type {PollingState} */ | ||
| 23 | const polling_state = { | 25 | const polling_state = { |
| 24 | timer_id: null, // 轮询定时器id | 26 | timer_id: null, // 轮询定时器id |
| 25 | running: false, // 是否正在轮询 | 27 | running: false, // 是否正在轮询 |
| ... | @@ -157,19 +159,31 @@ const ensure_network_listener = async () => { | ... | @@ -157,19 +159,31 @@ const ensure_network_listener = async () => { |
| 157 | 159 | ||
| 158 | /** | 160 | /** |
| 159 | * @description: 注销网络监听器 | 161 | * @description: 注销网络监听器 |
| 162 | + * 涉及字段: | ||
| 163 | + * - has_network_listener:是否有注册网络监听器 | ||
| 164 | + * - ref_count:引用计数 | ||
| 165 | + * - network_listener:网络状态变化监听器 | ||
| 166 | + * - network_usable:网络可用性状态 | ||
| 160 | */ | 167 | */ |
| 161 | 168 | ||
| 162 | const teardown_network_listener = () => { | 169 | const teardown_network_listener = () => { |
| 170 | + // 1. 前置校验:避免无效执行 | ||
| 171 | + // 如果没有注册网络监听器,直接返回 | ||
| 163 | if (!polling_state.has_network_listener) return | 172 | if (!polling_state.has_network_listener) return |
| 173 | + // 如果有引用计数,说明有其他地方在使用轮询,不能注销监听器 | ||
| 164 | if (polling_state.ref_count > 0) return | 174 | if (polling_state.ref_count > 0) return |
| 175 | + // 标记监听器已注销(核心状态更新) | ||
| 165 | polling_state.has_network_listener = false | 176 | polling_state.has_network_listener = false |
| 177 | + // 解绑框架层面的监听器 | ||
| 166 | if (polling_state.network_listener && typeof Taro.offNetworkStatusChange === 'function') { | 178 | if (polling_state.network_listener && typeof Taro.offNetworkStatusChange === 'function') { |
| 167 | try { | 179 | try { |
| 168 | Taro.offNetworkStatusChange(polling_state.network_listener) | 180 | Taro.offNetworkStatusChange(polling_state.network_listener) |
| 169 | } catch (e) { | 181 | } catch (e) { |
| 170 | - polling_state.network_listener = null | 182 | + // 捕获解绑失败的异常(比如监听器已被手动解绑) |
| 183 | + console.warn('注销网络监听器失败:', e) | ||
| 171 | } | 184 | } |
| 172 | } | 185 | } |
| 186 | + // 手动清空本地引用(关键!无论解绑成功/失败都要做) | ||
| 173 | // 注销后,清空网络监听器引用,确保后续调用能正常工作 | 187 | // 注销后,清空网络监听器引用,确保后续调用能正常工作 |
| 174 | polling_state.network_listener = null | 188 | polling_state.network_listener = null |
| 175 | /** | 189 | /** |
| ... | @@ -178,6 +192,7 @@ const teardown_network_listener = () => { | ... | @@ -178,6 +192,7 @@ const teardown_network_listener = () => { |
| 178 | * 设计思维:体现了 “状态闭环” 的工程化思想 —— 任何状态都要有明确的产生、更新、销毁逻辑,不残留 “脏数据” 干扰后续流程。 | 192 | * 设计思维:体现了 “状态闭环” 的工程化思想 —— 任何状态都要有明确的产生、更新、销毁逻辑,不残留 “脏数据” 干扰后续流程。 |
| 179 | */ | 193 | */ |
| 180 | // 清空网络可用性状态,确保后续判断逻辑能正常工作 | 194 | // 清空网络可用性状态,确保后续判断逻辑能正常工作 |
| 195 | + // 清空衍生状态,避免脏数据 | ||
| 181 | polling_state.network_usable = null | 196 | polling_state.network_usable = null |
| 182 | } | 197 | } |
| 183 | 198 | ... | ... |
-
Please register or login to post a comment