50+你可能不知道的 Web API

424 阅读7分钟

performance.now

performance.now() 方法返回一个精确到毫秒的毫秒数,记录了从页面打开到方法调用的时间差。

performance.now() / 1000 > 60 && alert("页面停留时间大于60S");

和 JavaScript 中其他可用的时间类函数(比如 Date.now )不同的是,performance.now() 返回的时间戳没有被限制在一毫秒的精确度内,相反,它们以浮点数的形式表示时间,精度最高可达微秒级。

另外一个不同点是,performance.now() 是以一个恒定的速率慢慢增加的,performance.timing.navigationStart + performance.now() 约等于 Date.now()。

PS:

这个时间戳实际上并不是高精度的。
为了降低像 Spectre 这样的安全威胁,各类浏览器对该类型的值做了不同程度上的四舍五入处理。(Firefox 从 Firefox 59 开始四舍五入到 2 毫秒精度)一些浏览器还可能对这个值作稍微的随机化处理。
这个值的精度在未来的版本中可能会再次改善,浏览器开发者还在调查这些时间测定攻击和如何更好的缓解这些攻击。

crypto.randomUUID

crypto.randomUUID() 方法用于使用加密安全随机数生成器 Crypto 生成 v4 UUID

快速生成 UUID,效果同:

export function uuid(): string {
  const tempUrl = URL.createObjectURL(new Blob());
  const uuid = tempUrl.toString();
  URL.revokeObjectURL(tempUrl);
  return uuid.slice(-36);
}
// 'bff149c1-d8c4-412d-8235-61ed4c4cef51'

此功能仅在安全上下文(HTTPS) 中可用,在某些或所有支持的浏览器中可用。

crypto.getRandomValues

Crypto.getRandomValues() 方法可以获取符合密码学要求的更为安全的随机值。

实际上,就是为了解决 Math.random() 有潜在的安全风险的问题,例如在 Node.js 服务层实现生成密钥或抽奖之类的功能。具体分析详见 在 NodeJS/Chrome/chromium 中预测 Math.random()

Intl.NumberFormat

Intl.NumberFormat 对象能使数字在特定的语言环境下格式化。

new Intl.NumberFormat().format(123456.789); // '123,456.789'

Intl 对象是 ECMAScript 国际化 API 的一个命名空间,它提供了精确的字符串对比、数字格式化,和日期时间格式化。NumberFormat 只是 Intl 其中的一个构造函数,提供了非常强大的功能,详细请参考 Intl.NumberFormat() constructor

Number.prototype.toLocaleString

Number.prototype.toLocaleString() 方法返回这个数字在特定语言环境下的表示字符串。在使用具有 Intl.NumberFormat API 支持的实现时,此方法仅仅简单调用了 Intl.NumberFormat

(123456.789).toLocaleString(); // '123,456.789'

en(de)codeURIComponent/en(de)codeURI/(un)escape

encodeURIComponent()decodeURIComponent()encodeURI()decodeURI()escape()unescape() 都是对统一资源标识符(URI)的组成部分进行编码/解码的方法。区别在于编码的执行范围和兼容性。

  • encodeURI() 方法不会对下列字符编码:URI 中具有特殊含义的 ASCII 标点符号(,/?: @&=+$#)

  • encodeURIComponent() 方法不会对下列字符编码:ASCII 字母、ASCII 数字、-_.!~*'()

(un)escape 函数已经从 Web 标准中删除,请不要使用该函数。

btoa/atob

btoa() 方法可以将一个二进制字符串编码为 Base64 编码的 ASCII 字符串。

你可以使用这个方法来对可能遇到通信问题的数据进行编码,然后使用 atob() 方法来对数据进行解码。

String.prototype.replace()

String.prototype.replace() 方法返回一个由替换值(replacement)替换部分或所有的模式(pattern)匹配项后的新字符串。模式可以是一个字符串或者一个正则表达式,替换值可以是一个字符串或者一个每次匹配都要调用的回调函数。如果 pattern 是字符串,则仅替换第一个匹配项。

"Yin Chengnuo".replace("n", "_"); // 'Yi_ Chengnuo'
"Yin Chengnuo".replace("C", "$$$$"); // 'Yin $$hengnuo'
"Yin Chengnuo".replace("C", "$&$&"); // 'Yin CChengnuo'
"Yin Chengnuo".replace("C", "$`"); // 'Yin Yin hengnuo'
"Yin Chengnuo".replace("C", "$'"); // 'Yin hengnuohengnuo'

"Yin Chengnuo".replace(/n/, "_"); // 'Yi_ Chengnuo'
"Yin Chengnuo".replace(/n/g, "_"); // 'Yi_ Che_g_uo'
"Yin Chengnuo".replace(/(\w+)\s(\w+)/, "$$"); // '$'
"Yin Chengnuo".replace(/(\w+)\s(\w+)/, "$&"); // 'Yin Chengnuo'
"Yin Chengnuo".replace(/n/g, "$`"); // 'YiYi CheYin ChegYin Chenguo'
"Yin Chengnuo".replace(/n/g, "$'"); // 'Yi Chengnuo Chegnuoguouo'
"Yin Chengnuo".replace(/(\w+)\s(\w+)/, "$2 $1"); // 'Chengnuo Yin'
"Yin Chengnuo".replace(/(\w+)\s(\w+)/, (s, $0, $1, $2) => $1 + " " + $0); // 'Chengnuo Yin'
// ...

String.prototype.padStart/padEnd

String.prototype.padStart() 方法用另一个字符串填充当前字符串(如果需要的话,会重复多次),以便产生的字符串达到给定的长度。从当前字符串的左侧开始填充。String.prototype.padEnd()从右侧填充。

"abc".padStart(10); // "       abc"
"abc".padStart(10, "foo"); // "foofoofabc"
"abc".padStart(6, "123465"); // "123abc"
"abc".padStart(8, "0"); // "00000abc"
"abc".padStart(1); // "abc"
crypto.getRandomValues(new Uint32Array(1))[0].toString().padEnd(10, "X"); // 524485109X

Array.prototype.sort

通常情况下,我们使用的 [/* ... */].sort(() => .5 - Math.random()) 对数组进行打乱顺序可能会使你的程序出大问题。

原因很简单:这不是真正意义上的完全乱序。

具体参考:如何将一个 JavaScript 数组打乱顺序?

下面是洗牌算法打乱数组排序的一个简单实现,请参考:

function shuffle(array) {
  var m = array.length,
    t,
    i;
  while (m) {
    i = Math.floor(Math.random() * m--);
    t = array[m];
    array[m] = array[i];
    array[i] = t;
  }
}

同时可以参考 lodash _.shuffle 的实现方式。

最后参考:不同算法 sort 效果预览

Node.textContent

Node.textContent 返回一个节点及其后代的文本内容。

与 innerText 的区别:

  • textContent 是 Node 对象属性,innerText 是 Element 对象属性

  • textContent 会获取所有元素的内容,包括 script 和 style 元素,然而 innerText 只能获取到可见元素的文本内容

  • textContent 会返回节点中的每一个元素。innerText 受 CSS 样式的影响,并且不会返回隐藏元素的文本。

  • textContent 只是单纯读取文本内容,因此性能更高。innerText 属性值的获取会考虑 CSS 样式,因此读取 innerText 的值将触发回流以确保计算出的样式是最新的。

Element.insertAdjacentHTML

Element.insertAdjacentHTML() 方法将指定的文本解析为 Element 元素,并将结果节点插入到 DOM 树中的指定位置。它不会重新解析它正在使用的元素,因此它不会破坏元素内的现有元素。这避免了额外的序列化步骤,使其比直接使用 innerHTML 操作更快。

DOMParser

DOMParser 可以将存储在字符串中的 XML 或 HTML 源代码解析为一个 DOM Document。

new DOMParser().parseFromString(
  '<span class="span">innerSpan</span>',
  "text/html"
).body.children[0]; // element 元素

以上两种方法本质上都是实现字符串转换为 DOM,详细请参考:盘点 HTML 字符串转 DOM 的各种方法及细节

Element.animate()

简单的说,Web Animations API 就是把 CSS3 实现的 animation 动画变成由 JS 代码实现。

@keyframes opacity {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

#app {
  animation: opacity 1s linear infinite;
}

同:

$("#app").animate([{ opacity: 1 }, { opacity: 0 }], {
  duration: 1000,
  easing: "linear",
  iterations: Infinity,
});

Element.scrollIntoView/scrollIntoViewIfNeeded

Element.scrollIntoView() 方法会滚动元素的父容器,使被调用 scrollIntoView() 的元素对用户可见。

Element.scrollIntoViewIfNeeded() 方法用来将不在浏览器窗口的可见区域内的元素滚动到浏览器窗口的可见区域。如果该元素已经在浏览器窗口的可见区域内,则不会发生滚动。此方法是 Element.scrollIntoView() 方法的专有变体,可能存在兼容问题。

URLSearchParams

URLSearchParams 接口定义了一些实用的方法来处理 URL 的查询字符串。

可以理解为 URL 的子接口,实际上 URL 对象内部确实也内置了 searchParams 对象。

const URI = "https://a.b.c/d/e?f=g&h=i#/j?k=l&m=n";
const url = new URL(URI);

console.log(url.searchParams.get("f")); // g
console.log(new URLSearchParams(url.search).get("f")); // g

IntersectionObserver

IntersectionObserver 可以监听一个元素和可视区域相交部分的比例,然后在可视比例达到某个阈值的时候触发回调。

MutationObserver

MutationObserver 可以监听对元素的属性的修改、对它的子节点的增删改。

ResizeObserver

ResizeObserver 可以用来监控元素盒子尺寸的变化。

实际上还有 PerformanceObserver 和 ReportingObserver 可以用来监听 performance 行为和过时 API,只是实在少用,故这里没有提及,以上使用见 浏览器的 5 种 Observer,你用过几种?

getComputedStyle

getComputedStyle() 方法用于获取指定元素的 CSS 样式。获取的样式是元素在浏览器中最终渲染效果的样式。该方法接受第二个参数用于获取元素伪元素样式。

KeyboardEvent/MouseEvent.getModifierState

MouseEvent.getModifierState()KeyboardEvent.getModifierState() 用法一致,都是为了返回指定修饰键(Shift、Control、CapLock 等)的当前状态,按下返回 true,否则返回 false。

queueMicrotask

queueMicrotask() 是浏览器内置标准的微任务调度方法,在一定场景上可以代替 Promise.resolve() 使用。

SpeechSynthesisUtterance

SpeechSynthesisUtteranceWeb Speech API 的子接口,简称语音合成,包含语音服务应阅读的内容以及有关如何阅读它的信息(例如语言、音调和音量)。

speechSynthesis.speak(new window.SpeechSynthesisUtterance("你好,世界!"));

MessageChannel

Channel Messaging API MessageChannel 接口允许我们创建一个新的消息通道,并通过它的两个 MessagePort 属性发送数据。一般用于跨脚本、iframe、worker等的通信。

BroadcastChannel

BroadcastChannel 是用于同源的不同浏览器窗口,Tab 页,frame 或者 iframe 下的不同文档之间相互通信。与 window.postMessage() 的区别就是不允许跨域。

CSSOM

CSS Object Model 是一组允许用 JavaScript 操纵 CSS 的 API。它是继 DOM 和 HTML API 之后,又一个操纵 CSS 的接口,从而能够动态地读取和修改 CSS 样式。

CSSOM 确实是一个比较复杂的模块,这里没有办法展开描述。如果具体项目中需要用到,请查看文档

操作 CSSOM 可以动态修改一些没有办法通过 DOM 修改的样式,比如动态修改伪类、伪元素及动画等 CSS 样式。

Clipboard API

剪贴板 Clipboard API 提供了响应剪贴板命令(剪切、复制和粘贴)与异步读写系统剪贴板的能力。

下面是一个从网页复制图片到剪切板的示例:

function copyImg () {
  const file = await (
    await showOpenFilePicker({
      types: [
        {
          description: "Images",
          accept: { "image/*": [".png", ".gif", ".jpeg", ".jpg"] },
        },
      ],
    })
  )[0].getFile();

  const blobFile = new Blob([file.slice()], { type: file.type });

  navigator.clipboard.write([
    new ClipboardItem({
      [blobFile.type]: blobFile,
    })
  ]);
};

Encoding API

Encoding API 提供了一种机制来处理各种字符编码文本,包括传统的非 UTF-8 编码。

下面是一个在 Web Serial API 中使用 TextDecoder 的示例:

const port = await navigator.serial.requestPort();

await port.open();

const reader = port.readable.getReader();
// 监听来自串口的数据
while (true) {
  const { value, done } = await reader.read();
  if (done) {
    reader.releaseLock();
    break;
  }
  console.log(new TextDecoder().decode(value));
}

Web Locks API

Web Locks API 允许一个脚本异步持有对资源的锁定,直到其处理完成之后再释放。

一般用于避免同一页面在不同 Tab 打开后同时操作页面也能带来的影响。

IdleDetector

IdleDetector 用于获取用户闲置状态,执行诸如与键盘、鼠标
屏幕长时间没有交互,执行页面保护程序激活、页面锁定或移动到其他页面之类的操作。

可能使用 IdleDetector API 的场景如下:

  • 聊天软件或在线社交网站可以使用此 API 来通知用户当前是否可以联系他们的联系人

  • 例如图书馆或高铁站大厅引导屏等展示程序类的应用可以通过这个 API 来在没有交互后返回首页。

然而目前看来这个特性只有 Chrome 支持,Firefox 和 Safari 出于保护用户隐私,都明确表示反对该特性。

然而我们仍然可以通过一些 polyfill 来实现类似功能,例如 VueUseuseIdle 的实现就是通过对 mousemove, mousedown, resize, keydown, touchstart, wheel 事件的监听来实现的。

AbortController

AbortController 接口表示一个控制器对象,允许你根据需要中止一个或多个 Web 请求。

const { abort, signal } = new AbortController();
const signal = controller.signal;
fetch(url, { signal })
  .then((response) => {
    console.log("下载完成");
  })
  .catch((err) => {
    console.error(`下载错误:${err.message}`);
  });

调用 abort 方法即可终止 fetch 并触发 fetch。

matchMedia

媒体查询可以看成是浏览器提供的获取⽤户系统参数和设置的接⼝。实际上除了 CSS,HTML , JavaScript 中也可以使用媒体查询。

<link rel="stylesheet" href="default.css" />
<link rel="stylesheet" href="mobile.css" media="(max-width: 480px)" />

if (matchMedia("(max-width: 480px)").matches) {
  // ...
}

JavaScript 中的媒体查询更为强大,下面是一个监听设置横竖屏的示例:

matchMedia("(orientation: landscape)").onchange = (e) => {
  if (e.matches) {
    console.log("请使用竖屏浏览页面");
  }
};

name

Window.name 用于获取/设置窗口的名称。

Window.name 有一个很有意思的点就是和 Tab 绑定而不是页面绑定,而且所有在同一个 Tab 的页面都可以修改这个属性,因此可以用来作为统一入口平台分发 token 使用。

PS:部分浏览器已经不支持使用 Window.name 跨域传递参数了。

Pointer Lock API

Pointer Lock API 提供了一种输入方法,这种方法是基于鼠标随着时间推移的运动的(也就是,deltas),而不仅是鼠标光标的绝对位置。通过它可以访问原始的鼠标运动,把鼠标事件的目标锁定到一个单独的元素,这就消除了鼠标在一个单独的方向上到底可以移动多远这方面的限制,并从视图中删去光标。简单来说:Pointer Lock API 的作用就是可以让你的鼠标无限移动,脱离浏览器窗体的限制。

document.currentScript

Document.currentScript 属性返回当前正在运行的脚本所属的 script 元素。

调用此属性的脚本不能是 JavaScript module,ES6 module 应当使用 import.meta 对象。

可用于类库封装、错误排查、前端监控等特殊功能实现。

document.referrer

Document.referrer 返回的是一个 URI,当前页面就是从这个 URI 所代表的页面跳转或打开的。

通常用于页面中返回上一页功能在弹出窗口的行为。

其他

此外,以下 Web API 是目前兼容性不是很好或者不常用但是十分值得关注的 API:

Battery Status API

Battery Status API 电池状态。

Barcode Detection API

Barcode Detection API 条码识别。

Cookie Store API

Cookie Store API 异步 cookie。

EyeDropper API

EyeDropper API 颜色拾取。

File System Access API

File System Access API 文件系统。

Navigation API

Navigation API 导航拦截。

Network Information API

Network Information API 网络监听。

SpeechRecognition

SpeechRecognition 语音识别。

Web Crypto API

Web Crypto API 前端加密。

WebTransport API

WebTransport API HTTP/3 版的 WebSocket。

Web Serial API

Web Serial API 串口通信。

Window Controls Overlay API

Window Controls Overlay API 自定义窗口。

Vibration API

Vibration API 手机震动。

Service Worker API

Service Worker API 前端代理服务器。

Storage Access API

Storage Access API 跨域 Storage 访问。

Permissions API

Permissions API 权限检测。