我正在开发一个长多页表单的SPA。重新加载时丢失表单状态是一种非常糟糕的用户体验。
由于这是一个SPA,浏览器将无法在重新加载后恢复表单状态。即使它可以,它也是一个多页面的表单,只显示字段的一个子集(尽管它可能填充隐藏的输入,正如我想到的那样)。
我可以使用历史状态来存储当前的表单状态,但我希望后退按钮能够回到以前的表单页面,而不清除当前页面上的进度。
我可以使用sessionStorage,但我需要存储文件和图像作为表单的一部分。+它是同步的
我本可以与服务器同步状态,但我不想将这种复杂性引入后端,特别是当感觉这个问题完全可以在客户端上解决时。
我正在考虑使用IndexedDB。但是,当表单状态不可访问并且需要清除时(例如,由于用户关闭选项卡),问题就出现了。
我可以想到解决它的一种方法是通过service worker,因为它有所有当前打开的选项卡列表(通过self.clients.matchAll()
API),并定期对与现在丢失的客户端id相关的数据进行垃圾收集。
不幸的是,为应用引入适当的service worker支持是一个相当复杂的跳跃。我宁愿推迟service worker的引入,直到我需要实现离线优先支持。
我在想,如果有不同的解决方案来解决spa中的表单持久性问题,这将需要更少的开发资源。
我假设您已经看到了"如果我不能在冻结或终止状态下运行异步api,我如何将数据保存到IndexedDB?"关于Page Lifecycle API的指南,因为使用service worker来持久化数据是其中一个选项。
另一种方法是在IDBTransaction
对象上使用commit()
方法,在关闭选项卡时执行有效的同步只写IDB操作。文章提到commit()
在当时并没有得到广泛支持,但是自从它最初编写以来,浏览器对它的支持已经有了很大的改进。
我想了无数种不同的方法来使用这种东西,但都无济于事。
pagehide
,beforeunload
和unload
的发射不够可靠(特别是在移动设备上)。
clients.matchAll()
不返回丢弃的客户端(在移动设备上有很多),这意味着它们的会话仍然可以恢复,而我的service worker会认为它们永远消失了(并且垃圾收集状态)。
对于表单状态,我可能会采用基于时间(或LRU)的驱逐策略。定期检查未使用的条目,例如,一年左右,或者当我运行接近提供的配额时,触发LRU驱逐。
理想情况下,这应该可以通过会话作用域IndexedDB实例轻松解决。我记得Jake Archibald说过他想在网络平台上做这样的事情。我认为这应该是一个很好的补充,老实说,没有多少人在web开发社区讨论这个问题(因为我无法通过谷歌找到我的问题的答案(也没有讨论))。老实说,我认为我们应该努力以这种方式改善用户体验。也许我应该让杰克知道这一点,让他(和网络工作组)知道确实需要它,而且……谁知道……也许有一天我们会看到它被实现。
到目前为止,不幸的是,这是一个未解决的问题,因为我仍然不是100%满意基于时间的驱逐。