让 HTML5 APP 离线工作

发布于 2022-10-03 23:27:53 字数 7275 浏览 141 评论 0

当您的 Web 浏览器与您的桌面绑定时,您从来没有在任何时候都无法获得 Internet 连接。

随着在移动设备上访问网络的能力显着提高——首先是在笔记本电脑上,然后是手机,现在是平板设备,现在无论您身在何处,都可以更轻松地访问您的数据和应用程序。 或者是吗?

这篇文章是在从伦敦到利物浦的火车上写的。 火车有 Wifi,我有 3G 数据卡,但我仍然没有完全连接。 此外,当今的许多在线工具都无法正确处理这种中间连接状态。

那么我们如何解决这个问题呢? 这并不简单,但您今天可以采取一些步骤,让您的用户无论身在何处都可以使用您的应用程序。 其中一些步骤在 HTML 中实现了直接解决方案; 有些需要您实现一些逻辑,所有这些都将帮助您构建更好的应用程序。

缓存您的资源

用户有条件在不在线时不输入 URL,因为他们知道他们会得到一个错误页面。 但它不必是这样的。 即使没有 Internet 连接,也可以构建可以加载的应用程序。

您应该构建您的应用程序以向您的用户呈现一致的 UI,以便即使他们处于离线状态,他们仍然可以看到和使用您的某些应用程序。 这将允许您检测网络连接的存在,并以优雅、友好的方式通知用户您的应用程序的连接要求。

按照我们的 AppCache 教程 ,您会发现很容易将其应用到现有应用程序中。 您的应用程序将包含一个指向清单文件的链接,该清单文件将包含包含您的应用程序的所有文件。

CACHE:
/js/logic.js
/js/options.js
/images/loading.png
/css/main.css

然后,浏览器会确保这些资产离线缓存,直到下次更新清单文件。

检测网络连接

现在,即使您处于离线状态,您也可以让您的应用程序加载并向您的用户呈现一致的界面,您需要检测何时有 Internet 连接。 如果您的应用程序需要 Internet 连接才能正常运行,这一点尤其重要。

HTML5 定义了一个事件,当您的应用程序连接时发出信号。 这是最简单的方法,但并非所有浏览器都支持。 也不保证准确。 API 的大多数实现都会监视本地网络接口的变化,以确定您的应用程序是否在线。 但是,如果您的网络接口已启动,但您的路由器已关闭,该怎么办? 你是离线还是在线?

通过查询 window.navigator.onLine 来检查你是否在线很简单

if (navigator.onLine) {
  alert('online')
} else {
  alert('offline');
}

You can also be told when there is a change in the network state. Just listen for the for the events on window.onOnline and window.onOffline

window.addEventListener("offline", function(e) {
  alert("offline");
}, false);

window.addEventListener("online", function(e) {
  alert("online");
}, false);

The API is straightforward, how do you get it to work if the API isn't implemented in the browser?

It is possible to use a couple more signals to detect if you are offline including side-effects of the AppCache and listening to the responses from XMLHttpRequest.

AppCache 错误事件

AppCache 系统总是尝试请求清单以检查它是否需要更新其资产列表。 如果该请求失败,通常是以下两种情况之一,即不再使用清单文件(即,它未托管)或系统无法访问网络以获取文件。

window.applicationCache.addEventListener("error", function(e) {
  alert("Error fetching manifest: a good chance we are offline");
});

检测到此请求失败可以很好地指示您是否有网络连接。

XMLHttpRequest

在您的应用程序使用过程中,网络连接可能会失败,那么您如何检测到呢?

今天构建的大量应用程序使用 XMLHttpRequest 从服务器获取数据,同时将用户保留在页面内。 XMLHttpRequest 定义了网络上发生错误时的事件。 您可以使用它来确定您是否有网络连接。

一旦构建了能够处理这些错误的应用程序,您就可以与 localStorage 方法进行交互,以在出现网络故障时存储和获取缓存数据。

以下代码是能够响应网络故障的 获取 函数的一个很好的示例。

var fetch = function(url, callback) {
  var xhr = new XMLHttpRequest();

  var noResponseTimer = setTimeout(function() {
    xhr.abort();
    if (!!localStorage[url]) {
      // We have some data cached, return that to the callback.
      callback(localStorage[url]);
      return;
    }
  }, maxWaitTime);

  xhr.onreadystatechange = function() {
    if (xhr.readyState != 4) {
      return;
    }

    if (xhr.status == 200) {
      clearTimeout(noResponseTimer);
      // Save the data to local storage
      localStorage[url] = xhr.responseText;
      // call the handler
      callback(xhr.responseText);
    }
    else {
      // There is an error of some kind, use our cached copy (if available).
      if (!!localStorage[url]) {
        // We have some data cached, return that to the callback.
        callback(localStorage[url]);
        return;
      }
    }
  };
  xhr.open("GET", url);
  xhr.send();
};

监视这个错误事件非常容易,但是将结果作为返回值传递出去很快就会变得很麻烦并且容易出错。 幸运的是,HTML DOM 具有丰富的事件机制,您可以使用它来创建自定义的 离线/在线 事件。

var fireEvent = function(name, data) {
  var e = document.createEvent("Event");
  e.initEvent(name, true, true);
  e.data = data;
  window.dispatchEvent(e);
};

将 fireEvent 方法集成到我们的 fetch 函数中,可以让我们根据网络连接响应事件,并让我们可以自由地构建与监视方法返回的数据无关的应用程序。

var fetch = function(url, callback) {
  var xhr = new XMLHttpRequest();

  var noResponseTimer = setTimeout(function() {
    xhr.abort();
    fireEvent("connectiontimeout", {});
    if (!!localStorage[url]) {
      // We have some data cached, return that to the callback.
      callback(localStorage[url]);
      return;
    }
  }, maxWaitTime);

  xhr.onreadystatechange = function(e) {
    if (xhr.readyState != 4) {
      return;
    }

    if (xhr.status == 200) {
      fireEvent("goodconnection", {});
      clearTimeout(noResponseTimer);
      // Save the data to local storage
      localStorage[url] = xhr.responseText;
      // call the handler
      callback(xhr.responseText);
    } else {
      fireEvent("connectionerror", {});
      // There is an error of some kind, use our cached copy (if available).
      if (!!localStorage[url]) {
        // We have some data cached, return that to the callback.
        callback(localStorage[url]);
        return;
      }
    }
  };
  xhr.open("GET", url);
  xhr.send();
};

我们现在可以构建应用程序,当网络中某处出现故障时会收到通知。

window.addEventListener("connectionerror", function(e) {
  alert("There is a connection error");
});

定期检查网络状态

使用与我们在 XML Http Request 示例中完全相同的结构,可以定期检查网络上的文件以查看是否存在网络连接。

setTimeout(function() { fetch("favicon.ico"); } , 30000);

谨慎使用它。 如果您的服务很受欢迎,这可能会增加流量。

缓存您的资产 第二部分:Bootstrapping

对 AppCache 的一个常见误解是认为必须缓存应用程序的所有逻辑和资产才能使其脱机运行。 不是这种情况。 您可以引导您的应用程序,使其进入可以向用户呈现用户界面的状态,并在运行时加载其余信息。

让我们看一个简单的例子:

-- index.html --
<html manifest="cache.manifest">

-- cache.manifest --
CACHE:
/js/logic.js
/js/options.js
/images/loading.png
/css/main.css

NETWORK:
*

它与第一章中的 AppCache 示例非常相似,但请注意包含“NETWORK:”部分。 每个不在 CACHE 部分中的数据请求都将被允许进入网络。

通过这个非常简单的方法,我们可以提供最少数量的资产来让应用程序运行,然后一旦我们检测到页面已经加载,我们可以使用加载的 JavaScript 来引入下一组更完整地定义的资产应用。

脚本加载器已在 Web 开发社区中获得认可,作为针对特定标准的加载脚本和其他目标的一种方式。 例如,如果您的浏览器不支持任何客户端存​​储,那么为什么要加载所有这些额外的代码呢?

将脚本加载器集成到您的项目中,同时将其与我们的离线支持测试相结合,可以让您构建让用户满意的应用程序。 下面是使用 YepNope JavaScript 框架的示例。

yepnope({
  test : isOnline,
  yep  : ['normal.js', 'controller.js', 'assets.js'],
  nope : 'errors.js'
});

上面的例子有点做作,但是你可以看到给定连接状态的知识,你可以很容易地在运行时开始加载更多的应用程序,并且,如果离线加载可以处理失败的不同脚本集案例。

缓存您的数据

我们在前面的示例“获取”请求中放弃了它。

为了使应用程序有用,您必须在客户端缓存您的应用程序使用的数据。 我们通过利用 localStorage API 的简单性实现了这一点。

XMLHttpRequest 框架发出的每个请求都可能成功或失败。 如果成功,我们会根据 URL 存储响应的结果。 如果失败,我们会检查 localStorage 是否存在请求的 URL,如果有数据,我们会返回该数据。

if (xhr.status == 200) {
  clearTimeout(noResponseTimer);
  // Save the data to local storage
  localStorage[url] = xhr.responseText;
  // call the handler
  callback(xhr.responseText);
}
else {
  // There is an error of some kind, use our cached copy (if available).
  if (!!localStorage[url]) {
    // We have some data cached, return that to the callback.
    callback(localStorage[url]);
    return;
  }
}

延伸阅读

HTML5Rocks 有许多 关于离线技术的教程 ,您可以在其中亲身体验代码示例。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

0 文章
0 评论
701 人气
更多

推荐作者

daid

文章 0 评论 0

我心依旧

文章 0 评论 0

晒暮凉

文章 0 评论 0

微信用户

文章 0 评论 0

DS

文章 0 评论 0

〆凄凉。

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文