Navigator

231 阅读2分钟

Navigator 接口表示用户代理的状态和标识。它允许脚本查询它和注册自己进行一些活动。

onLine

表明浏览器是否联网

if (navigator.onLine) {
  console.log("online");
} else {
  console.log("offline");
}

window.addEventListener("offline", (e) => {
  console.log("offline");
});

window.addEventListener("online", (e) => {
  console.log("online");
});

serviceWorker

ServiceWorkerContainer 对象用于提供注册、删除、更新。

if ('serviceWorker' in navigator) {
  // Supported!
}

userAgent

User-Agent 首部包含了一个特征字符串,用来让网络协议的对端来识别发起请求的用户代理软件的应用类型、操作系统、软件开发商以及版本号。

可以修改伪装, 比较混乱

User-Agent: Mozilla/<version> (<system-information>) <platform> (<platform-details>) <extensions>
  • Mozilla/[version] 浏览器名/版本,没有意义

  • <system-information> 分号隔开

  • <platform> (<platform-details>) 浏览器渲染引擎

  • <extensions> 扩展字段采用空格进行分隔

    • Chrome:Chrome/版本号
    • Safari:Safari/版本号 (历史原因,chrome浏览器后面也会带safari字段)
    • Version:Version/版本号 系统版本号
    • Mobile:移动设备标识,一般指内部版本号,苹果设备会带版本号,安卓设备不含版本号

User Agent列表.jpg

使用 Bowser 简化判断

const browserObject = bowser.parse(window.navigator.userAgent);
const { browser, os } = browserObject;
const { name: browserName, version: browserVersion } = browser;
const { name: osName, versionName: osVersionName } = os;
console.log(
    `${browserName} ${browserVersion} ${osName} ${osVersionName}`
);

geolocation

可访问设备的地理位位置信息

navigator.geolocation.getCurrentPosition(success, error, options)

  • success

    pos.coords

    • latitude 纬度
    • longitude 经度
    • accuracy 精确
  • error

    • code
    • message
  • options

    • enableHighAccuracy 是否使用其最高精度来表示结果
    • timeout 超时时间
    • maximumAge 0 不使用缓存
var options = {
    enableHighAccuracy: true,
    timeout: 5000,
    maximumAge: 0
};

function success(pos) {
    var crd = pos.coords;
    console.log('Your current position is:');
    console.log('Latitude : ' + crd.latitude);
    console.log('Longitude: ' + crd.longitude);
    console.log('More or less ' + crd.accuracy + ' meters.');
};

function error(err) {
    console.warn('ERROR(' + err.code + '): ' + err.message);
};

navigator.geolocation.getCurrentPosition(success, error, options);

sendBeacon

navigator.sendBeacon(url, data) 方法可用于通过 HTTP POST 将少量数据异步传输到 Web 服务器。

它主要用于将统计数据发送到 Web 服务器,同时避免了用传统技术发送分析数据的一些问题。

在文档卸载期间发送数据一直是一个困难。因为用户代理通常会忽略在 unload 事件处理器中产生的异步 XMLHttpRequest

过去,为了解决这个问题,统计和诊断代码通常要在

  • 发起一个同步 XMLHttpRequest 来发送数据。
  • 创建一个 <img> 元素并设置 src,大部分用户代理会延迟卸载(unload)文档以加载图像。
  • 创建一个几秒的 no-op 循环。
document.addEventListener("visibilitychange", function logData() {
  if (document.visibilityState === "hidden") {
    navigator.sendBeacon("/log", analyticsData);
  }
});
window.addEventListener(
  "pagehide",
  (event) => {
    if (event.persisted) {
      /* the page isn't being discarded, so it can be reused later */
    }
  },
  false,
);

避免使用 unload 和 beforeunload

  • 用户加载了网页并与其交互。
  • 完成浏览后,用户切换到了其他应用程序,而不是关闭选项卡。
  • 随后,用户通过手机的应用管理器关闭了浏览器应用。
  • unload 事件与现代浏览器实现的往返缓存(bfcache)不兼容
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Navigator.sendBeacon</title>
  </head>
  <body onload="analytics('start')" onunload="analytics('end')">
    <a id="target" href="https://baidu.com">click</a>
    <script>
      function log() {
        let xhr = new XMLHttpRequest();
        xhr.open("post", "/log", true);
        xhr.setRequestHeader(
          "Content-Type",
          "application/x-www-form-urlencoded"
        );
        xhr.send("foo=bar");
      }
      window.addEventListener("unload", function (event) {
        log();
        // a time-consuming operation
        for (let i = 1; i < 10000; i++) {
          for (let m = 1; m < 10000; m++) {
            continue;
          }
        }
      });

      const clickTime = 35000;
      const theLink = document.getElementById("target");
      theLink.addEventListener("click", function (event) {
        event.preventDefault();
        log();
        setTimeout(function () {
          window.location.href = theLink.getAttribute("href");
        }, clickTime);
      });

      window.addEventListener("unload", logData, false);
      function logData() {
        navigator.sendBeacon("/log", "foo=bar");
      }

      function analytics(state) {
        if (!navigator.sendBeacon) return;
        var URL = "http://example.com/analytics";
        var data = "state=" + state + "&location=" + window.location;
        navigator.sendBeacon(URL, data);
      }
    </script>
  </body>
</html>