使用 Firefox 1.5 缓存

Firefox 1.5 在单个浏览器会话期间,会将整个网页(包括其 JavaScript 状态)保存在内存中缓存。在已访问页面之间来回导航无需重新加载页面,JavaScript 状态也会得到保留。此功能被一些人称为 bfcache(“后退-前进缓存”的缩写),可大大加快页面导航速度。此缓存状态会一直保留,直到用户关闭浏览器。

在某些情况下,Firefox 不会缓存页面。以下是一些常见的导致页面未被缓存的程序化原因:

  • 页面使用了 unloadbeforeunload 事件处理程序;

  • 页面设置了“cache-control: no-store”。

  • 站点是 HTTPS 并且页面至少设置了以下任一项:

    • “Cache-Control: no-cache”
    • “Pragma: no-cache”
    • 设置了“Expires: 0”或“Expires”的值(相对于“Date”头的值,该值为过去的时间)(除非同时指定了“Cache-Control: max-age=”);
  • 用户导航离开页面时页面尚未完全加载,或由于其他原因(例如 XMLHttpRequest)存在待处理的网络请求;

  • 页面存在正在进行的 IndexedDB 事务;

  • 顶层页面包含框架(例如 <iframe>),而这些框架由于此处列出的任何原因都无法缓存;

  • 页面位于框架内,并且用户在该框架内加载了一个新页面(在这种情况下,当用户导航离开页面时,缓存的是最后加载到框架中的内容)。

此新的缓存功能改变了页面的加载行为,Web 作者可能希望:

  • 了解页面何时被导航(在从用户缓存加载时)
  • 定义用户离开页面时的页面行为(同时仍允许页面被缓存)

两个新的浏览器事件使 Web 作者能够同时实现这两点。

新的浏览器事件

如果您使用这些新事件,您的页面在其他浏览器中(我们已测试 Firefox、Internet Explorer、Opera 和 Safari 的早期版本)将继续正常显示,并在 Firefox 1.5 中加载时使用此新缓存功能。

注意:截至 2009 年 10 月,Safari 的开发版本已添加对这些新事件的支持(请参阅 WebKit bug)。

Web 页面的标准行为是:

  1. 用户导航到页面。
  2. 页面加载时,内嵌脚本会运行。
  3. 页面加载完成后,将触发 onload 事件处理程序。

某些页面包含第四个步骤。如果页面使用了 unloadbeforeunload 事件处理程序,则在用户导航离开页面时会触发它们。如果存在 unload 事件处理程序,则页面将不会被缓存。

当用户导航到已缓存的页面时,内嵌脚本和 onload 事件处理程序不会运行(步骤 2 和 3),因为在大多数情况下,这些脚本的效果已得到保留。

如果页面包含您希望每次用户导航到页面时都执行的脚本或其他行为,或者您想知道用户何时导航到已缓存的页面,请使用新的 pageshow 事件。

如果您有用户导航离开页面时触发的行为,但希望利用此新缓存功能,因此不想使用 unload 事件处理程序,请使用新的 pagehide 事件。

pageshow 事件

此事件的工作方式与 load 事件相同,不同之处在于它在页面每次加载时都会触发(而 load 事件在 Firefox 1.5 中从缓存加载页面时不会触发)。首次加载页面时,pageshow 事件在 load 事件触发后立即触发。pageshow 事件使用一个名为 persisted 的布尔属性,该属性在初始加载时设置为 false。如果不是初始加载(换句话说,当页面被缓存时),则设置为 true

将您希望在每次页面加载时运行的任何 JavaScript 设置为在 pageshow 事件触发时运行。

如果您在 pageshow 事件中调用 JavaScript 函数,可以通过调用 load 事件中的 pageshow 事件来确保这些函数在 Firefox 1.5 以外的浏览器中加载页面时被调用,如本文后面的示例所示。

pagehide 事件

如果您想定义用户导航离开页面时发生的行为,但又不想使用 unload 事件(这会导致页面不被缓存),可以使用新的 pagehide 事件。与 pageshow 类似,pagehide 事件也使用一个名为 persisted 的布尔属性。如果页面未被浏览器缓存,此属性设置为 false;如果页面被浏览器缓存,则设置为 true。当此属性设置为 false 时,如果存在 unload 事件处理程序,它将在 pagehide 事件之后立即触发。

Firefox 1.5 会尝试模拟与页面初始加载时相同的顺序的加载事件。框架的处理方式与顶层文档相同。如果页面包含框架,则在加载缓存页面时:

  • 每个框架的 pageshow 事件在主文档的 pageshow 事件之前触发。
  • 当用户导航离开缓存页面时,每个框架的 pagehide 事件在主文档的 pagehide 事件之前触发。
  • 对于单个框架内的导航,事件仅在受影响的框架中触发。

示例代码

下面的示例演示了一个使用 loadpageshow 事件的页面。此示例页面行为如下:

  • 在 Firefox 1.5 以外的浏览器中,每次加载页面时都会发生以下情况:load 事件触发 onLoad 函数,该函数调用 onPageShow 函数(以及一个附加函数)。
  • 在 Firefox 1.5 中,首次加载页面时,load 事件的运行方式与其他浏览器相同。此外,pageshow 事件也会触发,并且由于 persisted 设置为 false,不会发生其他操作。
  • 在 Firefox 1.5 中,当页面从缓存加载时,只有 pageshow 事件会触发。由于 persisted 设置为 true,只有 onPageShow 函数中的 JavaScript 操作会被触发。

在此示例中

  • 该页面每次加载页面时都会计算并显示当前日期和时间。此计算包括秒和毫秒,因此您可以轻松测试其功能。
  • 首次加载页面时,光标会放置在表单的“Name”字段中。在 Firefox 1.5 中,当用户返回到页面时,光标会保留在用户导航离开页面时的字段中。在其他浏览器中,光标会移回“Name”字段。
html
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
  <head>
    <title>Order query Firefox 1.5 Example</title>
    <style type="text/css">
      body,
      p {
        font-family: "Verdana", sans-serif;
        font-size: 12px;
      }
    </style>
    <script>
      function onLoad() {
        loadOnlyFirst();
        onPageShow();
      }

      function onPageShow() {
        // Calculate current time
        var currentTime = new Date();
        var year = currentTime.getFullYear();
        var month = currentTime.getMonth() + 1;
        var day = currentTime.getDate();
        var hour = currentTime.getHours();
        var min = currentTime.getMinutes();
        var sec = currentTime.getSeconds();
        var mil = currentTime.getMilliseconds();
        var displayTime =
          month +
          "/" +
          day +
          "/" +
          year +
          " " +
          hour +
          ":" +
          min +
          ":" +
          sec +
          ":" +
          mil;
        document.getElementById("time-field").value = displayTime;
      }

      function loadOnlyFirst() {
        document.zipForm.name.focus();
      }
    </script>
  </head>
  <body onload="onLoad();" onpageshow="if (event.persisted) onPageShow();">
    <h2>Order query</h2>

    <form
      name="zipForm"
      action="http://www.example.com/formresult.html"
      method="get">
      <label for="time-field">Date and time:</label>
      <input type="text" id="time-field" /><br />
      <label for="name">Name:</label>
      <input type="text" id="name" /><br />
      <label for="address">Email address:</label>
      <input type="text" id="address" /><br />
      <label for="order">Order number:</label>
      <input type="text" id="order" /><br />
      <input type="submit" name="submit" value="Submit Query" />
    </form>
  </body>
</html>

相比之下,如果上述页面不监听 pageshow 事件,而是在 load 事件中处理所有计算(而是按照以下代码片段示例所示编写),那么在 Firefox 1.5 中,当用户导航离开页面时,光标位置和日期/时间都将被缓存。当用户返回到页面时,将显示缓存的日期/时间。

html
<head>
  <script>
    function onLoad() {
      loadOnlyFirst();

      // Calculate current time
      var currentTime = new Date();
      var year = currentTime.getFullYear();
      var month = currentTime.getMonth() + 1;
      var day = currentTime.getDate();
      var hour = currentTime.getHours();
      var min = currentTime.getMinutes();
      var sec = currentTime.getSeconds();
      var mil = currentTime.getMilliseconds();
      var displayTime =
        month +
        "/" +
        day +
        "/" +
        year +
        " " +
        hour +
        ":" +
        min +
        ":" +
        sec +
        ":" +
        mil;
      document.getElementById("time-field").value = displayTime;
    }

    function loadOnlyFirst() {
      document.zipForm.name.focus();
    }
  </script>
</head>

<body onload="onLoad();"></body>

开发 Firefox 扩展

Firefox 1.5 扩展需要支持此缓存功能。如果您正在开发一个希望与 1.5 和早期版本兼容的 Firefox 扩展,请确保它监听 load 事件以触发可缓存的操作,并监听 pageshow 事件以触发不可缓存的操作。

例如,Google Toolbar for Firefox 需要监听 load 事件以进行自动链接功能,并监听 pageshow 事件以进行 PageRank 功能,才能与 1.5 和早期版本兼容。