浏览器返回的缓存问题

by.谢 郁 2017-6-14

缘起

写这篇文章源于一个需求:我们在账号注册、找回、设置的时候往往需要

entry => step1 => step2 => step3 => entry

那么到了entry页面之后,如果我们点击浏览器的返回,那么按理说是不能返回的

entey => step3 => step2 => step1 => entey

为了解决这个问题,我们需要用到history API,实现:

entey => step3 => step2 => step1 ———
  |                                |
  ———————————————back———————————————

浏览器的history API支持负数让我们返回指定索引的历史页面,因为我的这个需求是在手机APP里,可以保证entry一定是第一个页面,所以就比较好处理了:

history.go(-(history.length-1));

这样就实现了我们想要的效果,但是新的问题又出现了……

新的问题,浏览器返回机制不同

我们在entry页展示了用户的手机号,当用户修改完返回entry页,应该看到的是修改后的手机号。但是在不同浏览器下,其表现并不一致。某些浏览器(safari、baidu T7、UC等)下,返回后JS初始化代码不执行,所以不会从服务器拉取新的手机号(注意,这是浏览器机制,和缓存无关)。

举个更简单的例子:

alert('init');
$btn.on('click', function() {
    console('btn click');
});

返回后,alert不会执行,但是点击按钮后,console可以执行。

其实这些浏览器的机制也是有一定道理的:比如page1已经访问过了,返回后是之前访问时的状态,当我从page1 => page2, 如果在page1里的input填过东西,返回后就不用重新填写了,体验会比较好,可惜在这里成为了开发上的一个坑。

而我们熟悉的Chrome浏览器,在返回的时候仅仅是静态资源会走缓存,页面还是会初始化,所以不存在这个问题。

如何解决

1. 想办法让初始化JS执行(多页应用)

凡是会保存history快照的浏览器都不会真正销毁页面,当离开这个页面的时候,如果调用一个setTimeout延迟执行的函数,setTimeout内注册的回调函数会在再次进入该页面时入栈执行。所以可以这样解决:

var unload = isSafari ? 'pagehide' : 'unload'; //safari对unload的支持有问题,当然也可以直接使用pagehide
window.addEventListener(unload, function() {
    setTimeout(function () {
        init(); //页面初始化函数
    }, 200);
});
2. 想办法监听到用户点返回的动作(对于单页应用)

返回操作会触发浏览器的popstate事件,因此可以在这方面想办法,没有实践过,不过参考如何监听用户点击浏览器后退按钮这篇文章应该是可以做到的。

参考资料

赞一个(5)