所有文章 > AI驱动 > 不知道,但是可能超有用的 Web API

不知道,但是可能超有用的 Web API

前言

网页能展示什么能做什么,很大程度上是由浏览器宿这个主环境提供的基础能力决定的,这些能力就是  Web API[1],而这些基础能力也会时间发生变化。

近来重温WebAPI, 哇塞,变化不少,总结分享一些个人觉得比较实用的 已实现(部分实现)或者未实现的一些有意思的 Web API.

此外,Web API新增了很多与硬件相关的API, 比如USB,摄像头的,视频编码等等,显然是野心勃勃。

信息来源

  • MDN Web API[2]
  • W3C standards and drafts 之 Web API[3]
  • W3C (World Wide Web Consortium)
    • W3C制定了许多与Web服务、数据交换格式等相关标准,如XML、JSON-LD、SOAP等。你可以访问其官方网站 https://www.w3.org/ ,在“Standards”部分查找相关信息。
  • IETF (Internet Engineering Task Force)
    • IETF负责定义互联网相关协议和技术标准,包括HTTP、HTTPS、WebSocket等,这些都是构建Web API的基础。通过访问IETF的RFC索引(https://www.rfc-editor.org/rfc-index.html),可以查看和下载相关的RFC文档。[4]
  • WHATWG (Web Hypertext Application Technology Working Group)
    • WHATWG致力于HTML、DOM以及其他Web平台技术的标准化工作,部分API的设计和规范可通过其官方网站 https://whatwg.org/ 获取。

清单

相关demo 的源码,可以从 juejinBlogsCodes WebApi[5] 获取。

名称功能
Screen Wake Lock API[6]能够防止设备因为闲置而自动调低亮度或锁定屏幕
Cookie Store API[7]更加便捷获取和设置cookie的信息
Compression Stream API[8]使用 gzip 或者默认格式压缩和解压缩数据
CSS Custom Highlight API[9]JavaScript 创建范围并使用 CSS 定义样式来设置文档中任意文本范围的样式
EyeDropper[10]从屏幕上选择颜色
Prioritized Task Scheduling API[11]对任务优先级进行控制
Trusted Types API[12]为Web开发者提供了一种锁定DOM(文档对象模型)API中易受攻击部分的方法
CSS Font Loading API[13]动态加载字体资源的事件和接口
Popover API[14]内置的弹框能力
URL Pattern API[15]URL匹配器, 类似path-to-regex
Audio Output Devices API[16]音频输出选择能力
Device Memory API[17]获取内存信息
Barcode Detection API[18]用于检测图像中的条形码和二维码

Screen Wake Lock API[19]

Screen Wake Lock API 提供了一种方法,使得当应用程序需要保持运行时,能够防止设备因为闲置而自动调低亮度或锁定屏幕。
这对于诸如视频会议、演示文稿、实时游戏、在线教育等需要用户持续关注且不允许屏幕熄灭的应用场景尤其有用。通过使用这个API,即使在没有用户交互的情况下,开发者也能确保屏幕始终保持开启状态。

简简单单30行代码,就能控制和监听 屏幕唤醒锁。

<button onclick="onLockScreen()">锁屏</button>
<button onclick="onUnlockScreen()">释放</button>

<div id="statusElem"></div>
<script>
let wakeLock = null;
async function onLockScreen() {
// create an async function to request a wake lock
try {
wakeLock = await navigator.wakeLock.request("screen");
statusElem.textContent = "唤醒锁已激活";

wakeLock.addEventListener("release", () => {
// the wake lock has been released
statusElem.textContent = "唤醒锁已释放";
});
} catch (err) {
// The Wake Lock request has failed - usually system related, such as battery.
statusElem.textContent = `${err.name}, ${err.message}`;
}
}
async function onUnlockScreen() {
if (!wakeLock) return;
wakeLock.release().then(() => {
wakeLock = null;
});
}
</script>

截图_20242212092253.png

Cookie Store API[20]

按照以往,开发者如何获得cookie信息呢,当然是 document.cookie,

截图_20240310232535.png

这种的缺点是没法知道 domainpathexpired等信息。

当然,开发者借用开发者工具,可以获取更加详细的信息:

截图_20240310232700.png

Cookie Store API[21] 可以获得开发工具一样的cookie属性,当然 具有 HttpOnly的属性的是获取不到的。

截图_20240310232916.png

当然还提供了

  • cookieStore.delete[22]: 删除
  • cookieStore.get[23]: 获取单个cookie信息
  • cookieStore.set[24]: 设置单个cookie信息

Compression Stream API[25]

Compression Stream API 提供了一种 JavaScript API,使用 gzip 或者默认格式压缩和解压缩数据流。内置的压缩库意味着 JavaScript 应用不再需要包含其它压缩库,这使得应用程序的下载大小更小。

比如下面的就是上传一个文本文件到浏览器,代码采用gzip压缩纯文本后,从6kb变为了1kb,解压缩后又变成了6kb。

截图_20242612102650.png

代码嘛,简简单单。

<input type="file" id="file" >
<script>
async function compressAndDownload(filename, content) {
// 创建原始数据流
const stringStream = new ReadableStream({
start(controller) {
controller.enqueue(new TextEncoder().encode(content));
controller.close();
}
});

// 创建压缩流
const compressionStream = new CompressionStream('gzip');

// 将原始数据流连接到压缩流
const compressedStream = stringStream.pipeThrough(compressionStream);

// 创建ArrayBuffer容器接收压缩数据
const chunks = [];
const reader = compressedStream.getReader();
try {
while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
}
} finally {
reader.releaseLock();
}

// 合并压缩数据并创建Blob
const compressedBlob = new Blob(chunks, { type: 'application/gzip' });

// 创建下载链接
const url = URL.createObjectURL(compressedBlob);
const link = document.createElement('a');
link.href = url;
link.download = `${filename}.gz`;
document.body.appendChild(link);

// 触发下载
link.click();

// 清理
setTimeout(() => {
document.body.removeChild(link);
URL.revokeObjectURL(url);
}, 0);
}


file.addEventListener('change', async (event) => {
if(event.target.files.length === 0){
return;
}
const file = event.target.files[0];
const reader = new FileReader();
reader.readAsText(event.target.files[0]);
reader.onload = async () => {
const content = reader.result;
compressAndDownload(file.name, content);
}
})
</script>

CSS Custom Highlight API[26]

CSS 自定义高亮 API 提供了一种方法,可以通过使用 JavaScript 创建范围并使用 CSS 定义样式来设置文档中任意文本范围的样式。

感兴趣的同学,可以去 MDN 在线的示例 进行实操 CSS Custom Highlight API#Result[27]

截图_20243812103845.png

其逻辑是就是查找所有文本节点,收集匹配内容的Range, 最后作为参数构建 HighLight对象, 需要注意的是其 并未产生新的节点

核心逻辑代码如下:

const query = document.getElementById("query");
const article = document.querySelector("article");

// Find all text nodes in the article. We'll search within these text nodes.
const treeWalker = document.createTreeWalker(article, NodeFilter.SHOW_TEXT);
const allTextNodes = [];
let currentNode = treeWalker.nextNode();
while (currentNode) {
allTextNodes.push(currentNode);
currentNode = treeWalker.nextNode();
}
// Listen to the input event to run the search.
query.addEventListener("input", () => {
// If the CSS Custom Highlight API is not supported, display a message and bail-out.
if (!CSS.highlights) {
article.textContent = "CSS Custom Highlight API not supported.";
return;
}

// Clear the HighlightRegistry to remove the previous search results.
CSS.highlights.clear();

// Clean-up the search query and bail-out if if it's empty.
const str = query.value.trim().toLowerCase();
if (!str) {
return;
}

// Iterate over all text nodes and find matches.
const ranges = allTextNodes
.map((el) => {
return { el, text: el.textContent.toLowerCase() };
})
.map(({ text, el }) => {
const indices = [];
let startPos = 0;
while (startPos < text.length) {
const index = text.indexOf(str, startPos);
if (index === -1) break;
indices.push(index);
startPos = index + str.length;
}

// Create a range object for each instance of str we found in the text node.
return indices.map((index) => {
const range = new Range();
range.setStart(el, index);
range.setEnd(el, index + str.length);
return range;
});
});

// Create a Highlight object for the ranges.
const searchResultsHighlight = new Highlight(...ranges.flat());

// Register the Highlight object in the registry.
CSS.highlights.set("search-results", searchResultsHighlight);
});

EyeDropper[28]

可以打开并使用它从屏幕上选择颜色。

记住了,是从屏幕上拾取颜色, 下面的截图就是从浏览器外的背景桌面拾取了衣服的颜色, 真不错。

基于这个做个取色插件,是不是分分钟就搞定呢?

截图_20242312032354.png

代码,简简单单二三十行:

 <button id="start-button">打开拾色器</button>
<img src="https://img.alicdn.com/imgextra/i1/O1CN01CC9kic1ig1r4sAY5d_!!6000000004441-2-tps-880-210.png" />
<div>
颜色是:<span id="result"></span>
</div>
<script>
document.getElementById("start-button").addEventListener("click", () => {
const resultElement = document.getElementById("result");

if (!window.EyeDropper) {
resultElement.textContent = "你的浏览器不支持 EyeDropper API";
return;
}

const eyeDropper = new EyeDropper();
const abortController = new AbortController();

eyeDropper
.open({ signal: abortController.signal })
.then((result) => {
resultElement.textContent = result.sRGBHex;
resultElement.style.backgroundColor = result.sRGBHex;
})
.catch((e) => {
resultElement.textContent = e;
});
});

</script>

Prioritized Task Scheduling API[29]

提供了一种标准化的方法,用于对属于应用程序的所有任务进行优先级排序。

优先级任务调度API允许开发者为异步任务分配优先级,这些任务按照以下三种优先级顺序执行:

  1. user-blocking这类任务优先级最高,它们直接影响用户的交互体验。这类任务主要包括页面渲染至可交互状态的过程,以及对用户输入的即时响应。例如,页面初次加载的核心内容渲染、按钮点击事件的处理等。
  2. user-visible:这类任务虽可见于用户界面,但并不阻止用户继续进行其他操作。这类任务包括渲染页面的非关键部分,例如非核心图片加载、非关键动画渲染等。这是默认的优先级等级。
  3. background优先级最低的一类任务,它们对时间要求不严苛,可以在不影响用户体验的前提下稍后执行。这类任务包括日志处理、非必需的第三方库初始化以及其他不影响页面即时呈现的工作。这些任务通常在主线程空闲时执行,以避免阻塞用户可见或交互相关的高优先级任务。

欸,这就给高端玩家无限遐想了,只能一个字表达  太牛了

下面一个例子,来看看优先级的输出情况, 可以看到,如你所愿:

    <div id="log"></div>
<script>
let log = document.getElementById("log");
function mylog(text) {
log.innerHTML += `${text}<br/>`;
}

// three tasks, in reverse order of priority
scheduler.postTask(() => mylog("background 1"), { priority: "background" });
scheduler.postTask(() => mylog("user-visible 1"), { priority: "user-visible" });
scheduler.postTask(() => mylog("user-blocking 1"), { priority: "user-blocking" });

// three more tasks, in reverse order of priority
scheduler.postTask(() => mylog("background 2"), { priority: "background" });
scheduler.postTask(() => mylog("user-visible 2"), { priority: "user-visible" });
scheduler.postTask(() => mylog("user-blocking 2"), { priority: "user-blocking" });

// Task with default priority: user-visible
scheduler.postTask(() => mylog("user-visible 3 (default)"));

</script>

截图_20240012040015.png

Trusted Types API[30]

Web开发者提供了一种锁定DOM API中不安全部分的方法,目的是防止客户端跨站脚本(Cross-site scripting,XSS)攻击

在下面的例子中,通过TrustedTypePolicyFactory.createPolicy()方法创建一个策略,通过TrustedTypePolicy.createHTML方法创建一个安全的HTML字符串插入到文档中。

有很大的灵活性,策略是自己可以定义的。

<div id="myDiv"></div>

<script>

var entityMap = {
"&": "&amp;",
"<": "&lt;",
">": "&gt;",
'"': '&quot;',
"'": ''',
"/": '/'
};
// 创建一个策略,该策略将用于将不受信任的输入转换为安全的内容。
const escapeHTMLPolicy = trustedTypes.createPolicy("myEscapePolicy", {
createHTML: (string) => string.replace(/[&<>"'\/]/g, function (s) {
return entityMap[s];
}),
});

let el = document.getElementById("myDiv");
const escaped = escapeHTMLPolicy.createHTML("<img src=x onerror=alert(1)>");
console.log(escaped instanceof TrustedHTML); // true
el.innerHTML = escaped;

</script>

除此之外,还可以用来创建用来检查 Script 和 ScriptURL的策略。

const policy = trustedTypes.createPolicy("myPolicy", {
createScriptURL: (s, type, sink) => { //......},
createScript: (s) => { //......}
});

CSS Font Loading API[31]

CSS 字体加载 API 为你提供了动态加载字体资源的事件和接口。

以往引入字体主要是靠 css 来实现的, 动态引入字体也可以通过动态添加link节点来实现。

@font-face {
2 font-family: 'MyCustomFont';
3 src: url('fonts/mycustomfont.woff2') format('woff2'),
4 url('fonts/mycustomfont.woff') format('woff');
5 font-weight: normal;
6 font-style: normal;
7}

现在呢, 内置了原生AP, 能动态加载字体,而且能控制加载时机,以及加载的状态。

const font = new FontFace("myfont", "url(myfont.woff)", {
style: "italic",
weight: "400",
stretch: "condensed",
});

// 加载字体
font.load().then(()=>{
// 加载完毕
}, (err) => {
// 加载异常
console.error(err);
},);

// 等待到所有的字体都加载完毕
document.fonts.ready.then(() => {
// 使用该字体渲染文字(如:在 canvas 中绘制)
});

Popover API[32]

Popover API为开发者提供了一个标准、一致且灵活的机制,用于在页面其他内容之上展示弹出内容。这种弹出内容可以通过HTML属性声明性控制,也可以通过JavaScript编程方式进行控制。

下面的例子就是 0 行javascript实现的弹框。

图片
截图_20245312015341.png

可以在 Using the Popover API#Result[33] 查看源码和体验, 还可以在 MDN Popover API examples[34] 看到更多的示例

URL Pattern API[35]

URL Pattern API 定义了一种语法,该语法用于创建URL模式匹配器。这些模式能够与完整的URL或URL的各个组成部分进行匹配。其借鉴了 path-to-regexp[36]的语法。

path-to-regexp[37] 这个库你也许不知道吗,但是你一定用过, express , koa-touer 等等底层路由都是依赖这个库。

匹配模块包含:URL Pattern API 的模式语法包括:

  1. 字面字符串:将精确匹配的文本字符串,例如 “/home” 或 “/contact”。
  2. 通配符:如 “/posts/ ” 中的星号 ( ) 表示匹配任何字符序列,直至遇到下一个路径分隔符(/)。
  3. 命名组:如 “/books/:id” 中的 “:id”,它会提取匹配URL中对应部分的值,作为单独的数据项。
  4. 非捕获组:如 “/books{/old}?”,这里的花括号 {...}? 表示该部分模式是可选的,可以匹配0次或1次,且不会作为一个单独的数据项提取出来。
  5. 正则表达式组:如 “/books/(\d+)” 中的 (\d+),这部分遵循JavaScript正则表达式的规则,用于进行复杂匹配,尽管在URL Pattern API中有一定的限制。例如,此处的正则表达式将匹配一个或多个数字字符,并将其作为一个独立的数据项提取出来。
// A pattern matching with a named group
const pattern = new URLPattern({ pathname: "/books/:id" });
console.log(pattern.test("https://example.com/books/123")); // true
console.log(pattern.exec("https://example.com/books/123").pathname.groups); // { id: '123' }

Audio Output Devices API[38]

音频输出设备API(Audio Output Devices API)赋予了Web应用程序能力,使其能够询问用户希望使用哪个音频输出设备进行声音播放。

欸, 可以选择音频输出设备,还是比较有意思的。协议原文 Audio Output Devices API[39], 可惜还没有浏览器支持。

document.querySelector("#myButton").addEventListener("click", async () => {
if (!navigator.mediaDevices.selectAudioOutput) {
console.log("selectAudioOutput() not supported or not in secure context.");
return;
}

// Display prompt to select device
const audioDevice = await navigator.mediaDevices.selectAudioOutput();

// Create an audio element and start playing audio on the default device
const audio = document.createElement("audio");
audio.src = "https://example.com/audio.mp3";
audio.play();

// Change the sink to the selected audio output device.
audio.setSinkId(audioDevice.deviceId);
});

Device Memory API[40]

传统上,开发人员评估客户端设备性能时,由于无法直接获取设备的RAM大小信息,他们往往需要采取一些经验法则,或是通过设备基准测试,抑或是根据设备制造商、用户代理(User Agent)字符串等其他因素间接推测设备能力。

但现在,有以下两种方法可以直接或间接确定设备的大致RAM量:

  1. Device Memory JavaScript API:这个API为开发者提供了一种直接了解设备内存(RAM)容量的方式。通过navigator.deviceMemory属性,可以获得设备内存级别的大致信息,如0.5表示小于1GB的RAM,1表示1-2GB,以此类推。
  2. 接受Client Hints:客户端提示(Client Hints)是一种HTTP协议扩展,允许浏览器在HTTP请求中主动发送设备能力相关信息。其中,Device-Memory HTTP请求头就包含了设备的内存类别信息。虽然这不是直接在JavaScript中获取,但服务器可以根据这个头信息动态调整响应内容,帮助开发者根据设备RAM大小优化用户体验。
const RAM = navigator.deviceMemory;  // 8

值是 0.250.51248之一,所以机器 16G内存,显示的也是8。

Barcode Detection API[41]

用于检测图像中的条形码和二维码。

欸, 这就很有意思,配和 navigator.mediaDevices.getUserMedia唤起摄像头,定期截图分析,是不是就是一个web版本的扫码能力呢?

截图_20245712025755.png

if (!("BarcodeDetector" in globalThis)) {
console.log("此浏览器不支持条形码检测器。");
} else {
console.log("条形码检测器是支持的!");

// 创建新检测器
const barcodeDetector = new BarcodeDetector({
formats: ["code_39", "codabar", "ean_13"],
});

barcodeDetector
.detect(imageEl)
.then((barcodes) => {
barcodes.forEach((barcode) => console.log(barcode.rawValue));
})
.catch((err) => {
console.log(err);
});

}

CSS Typed Object Model API[42]

CSS Typed Object Model(CSSOM)API从根本上改变了开发者在JavaScript中处理CSS属性的方式,通过引入类型安全性和效率优化。

比如:简简单单就能获取样式的键值对, 其实还有一个结果有类似功能API window.getComputedStyle

本文章转载微信公众号@成长的程序世界

#你可能也喜欢这些API文章!